V8SORT spoj – sắp xếp

Nguồn đề bài: http://vn.spoj.com/problems/V8SORT/

1. Đề bài V8SORT spoj

Cho một dãy số. Bạn cần sắp xếp dãy số bằng cách đổi chỗ các cặp phần tử. Chi phí để đổi chỗ phần tử hai ở vị trí i và vị trí j là Cij.

Nhiệm vụ của bạn là tìm chi phí nhỏ nhất để có thể sắp xếp dãy số theo thứ tự tăng dần.

Dữ liệu

  • Dòng đầu tiên chứa dãy số cần sắp xếp, có số phần tử không vượt quá 7.
  • Dòng thứ i trong số N dòng tiếp theo chứa N số nguyên, số thứ j cho biết Cij, chi phí để đổi chỗ phần tử ở vị trí thứ i và vị trí thứ j. Biết N là số phần tử của dãy số, các phần tử được đánh số từ 1 đến N từ trái sang phải. 0 ≤ Cij ≤ 999, Cii=0 và Cij=Cji.

Kết quả

In ra một số nguyên dương duy nhất: tổng chi phí nhỏ nhất để sắp xếp dãy số theo thứ tự tăng dần.

Ví dụ

Dữ liệuKết quả
1 2 3 4 6 5
0 1 2 3 4 5
1 0 1 2 3 4
2 1 0 1 2 3
3 2 1 0 1 2
4 3 2 1 0 900
5 4 3 2 900 0
4

2. Gợi ý V8SORT spoj

Ta để ý, số phần tử không quá 7.

Có bạn bảo là quay lui. Nhưng mình vẫn chưa nghĩ ra phải quay thế nào và khi nào thì dừng lại.

Ở đây mình gợi ý giải bằng phương pháp đồ thị. Ta đưa về bài toán tìm đường đi ngắn nhất với trọng số không âm. Sử dụng Dijkstra.

Ví dụ test mẫu, ta coi trạng thái dãy 1,2,3,4,6,5 là một đỉnh có chỉ số 123465 thì đỉnh kề với nó có thể là 213465(chi phí c12) , 321465(chi phí c13), 423165(chi phí c14),… (đổi chỗ 2 kí tự).

Để xây dựng được đồ thị, ta cần nén dãy ban đầu lại thành n phần tử có giá trị từ 1 -> n

=> sắp xếp để dãy thành 1,2,3,4,…,n. Sau đó ta chuyển trạng thái của dãy thành 1 đỉnh có chỉ số tạo thành bởi cách viết liên tiếp dãy đó. Để chuyển thì các bạn có thể viết 1 hàm riêng hoặc trong C có thể sử dụng hàm có sẵn. Vì n<=7 nên ta có max là 7654321 đỉnh.

3. Code mẫu V8SORT spoj

#include <bits/stdc++.h>
 
using namespace std;
typedef pair<int,int> II;
    char s[7];
    int a[10],n,f[7654325],x[10],cl[7654325],c[10][10];
    set<II> q;
int taoso()
{
    int u=0;
    for(int i=1; i<=n; i++)
        u=u*10+a[i];
    return u;
}
int taoen()
{
    int u=0;
    for(int i=1; i<=n; i++)
        if(a[i])
            u=u*10+i;
        else u=u*10;
    return u;
}
bool ok(int u,int i,int j)
{
    if(i==j) return 0;
    sprintf(s,"%d",u);
    if(s[i-1]=='0'||s[j-1]=='0')
        return 0;
    return 1;
}
int doi(int u,int i,int j)
{
    sprintf(s,"%d",u);
    swap(s[i-1],s[j-1]);
    sscanf(s,"%d",&u);
    return u;
}
void dij()
{
    int u,v;
    II t;
    int st=taoso();
    int en=taoen();
    cl[st]=1;
    f[st]=0;
    q.insert(II(0,st));
    while(!q.empty())
    {
        t=*q.begin();
        q.erase(t);
        u=t.second;
        if(u==en)
            {
                printf("%d",f[u]);
                return;
            }
        for(int i=1; i<=7; i++)
        for(int j=1; j<=7; j++)
            if(ok(u,i,j))
            {
                v=doi(u,i,j);
                if(cl[v]==0)
                {
                    cl[v]=1;
                    f[v]=f[u]+c[i][j];
                    q.insert(II(f[v],v));
                } else
                if(f[v]>f[u]+c[i][j])
                {
                    q.erase(II(f[v],v));
                    f[v]=f[u]+c[i][j];
                    q.insert(II(f[v],v));
                }
            }
    }
}
int main()
{
    //freopen("v8sort.inp","r",stdin);
    ios::sync_with_stdio(0);
    n=0;
    gets(s);
    char* st=strtok(s," ");
    while(st!=NULL)
    {
        sscanf(st,"%d",&a[++n]);
        x[n]=a[n];
        st=strtok(NULL," ");
    }
    sort(x+1,x+n+1);
    for(int i=1; i<=n; i++)
        a[i]=lower_bound(x+1,x+n+1,a[i])-x;
    for(int i=1; i<=n; i++)
    for(int j=1; j<=n; j++)
        scanf("%d",&c[i][j]);
    while(n<7)
        a[++n]=0;
    dij();
}

One thought on “V8SORT spoj – sắp xếp

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *