1. 程式人生 > >【HDU 5402】Travelling Salesman Problem(構造)

【HDU 5402】Travelling Salesman Problem(構造)

被某題卡SB了,結果這題也沒讀好。。。以為每個格子可以有負數就當搜尋做了,怎麼想也搜不過去,後來發現每個格子是非負數,那麼肯定就是構造題。

題解如下:

首先如果nn為奇數或者mm為奇數,那麼顯然可以遍歷整個棋盤。

如果n,mn,m都為偶數,那麼講棋盤黑白染色,假設(1,1)(1,1)(n,m)(n,m)都為黑色,那麼這條路徑中黑格個數比白格個數多11,而棋盤中黑白格子個數相同,所以必然有一個白格不會被經過,所以選擇白格中權值最小的不經過。

構造方法是這樣,首先RRRRDLLLLD這樣的路徑走到這個格子所在行或者上一行,然後DRUR這樣走到這個格子的所在列或者前一列,然後繞過這個格子。然後走完這兩行,接著按LLLLDRRRR這樣的路徑往下走。


這題需要說明一下為什麼這麼選,因為如果你選的不是 (i,j)互為奇偶的格子的話,肯定有其餘的(i,j)互為奇偶的格子不能被走到,如果選擇的話,只有這一個格子不會被走到,所以根據貪心肯定要選這個格子了.

恩。。挺腦洞的一題,寫起來倒是不難。

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 105;
const int  INF = (1 << 30);
int mat[maxn][maxn];
int n,m,sum,minv,posx,posy;
void special_solve(){
    printf("%d\n",sum - minv);
    if(!(posx & 1)){
        for(int i = 0; i < posx; i++){
            char c = i & 1 ? 'L' : 'R';
            for(int j = 1; j < m; j++)
                printf("%c",c);
            printf("D");
        }
        int base = 0;
        for(int i = 0; i < m; i++){
            char c = (i + base) & 1 ? 'U' : 'D';
            if(i != posy)
                printf("%c",c);
            else
                base ++;
            if(i < m - 1)
                printf("R");
        }
        for(int i = posx + 2; i < n; i++){
            printf("D");
            char c = i & 1 ? 'R' : 'L';
            for(int j = 1; j < m; j++)
                printf("%c",c);
        }
    }
    else{
        for(int i = 0; i < posx - 1; i++){
            char c = i & 1 ? 'L' : 'R';
            for(int j = 1; j < m; j++)
                printf("%c",c);
            printf("D");
        }
        int base = 0;
        for(int i = 0; i < m; i++){
            char c = (i + base) & 1 ? 'U' : 'D';
            if(i != posy)
                printf("%c",c);
            else
                base ++;
            if(i < m - 1)
                printf("R");
        }
        for(int i = posx + 1; i < n; i++){
            printf("D");
            char c = i & 1 ? 'R' : 'L';
            for(int j = 1; j < m; j++)
                printf("%c",c);
        }
    }
}
int main(){
    while(scanf("%d%d",&n,&m) != EOF){
        sum = 0;
        minv = INF;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++){
                scanf("%d",&mat[i][j]);
                sum += mat[i][j];
                if((i + j) & 1){
                    if(minv > mat[i][j]){
                        posx = i;
                        posy = j;
                        minv = mat[i][j];
                    }
                }
            }
        if(n & 1){
            printf("%d\n",sum);
            for(int i = 0; i < n; i++){
                char c = i & 1 ? 'L' : 'R';
                for(int j = 1; j < m; j++)
                    printf("%c",c);
                if(i != n - 1)
                    printf("D");
            }
        }
        else if(m & 1){
            printf("%d\n",sum);
            for(int i = 0; i < m; i++){
                char c = i & 1 ? 'U' : 'D';
                for(int j = 1; j < n; j++)
                    printf("%c",c);
                if(i != m - 1)
                    printf("R");
            }
        }
        else
            special_solve();
        puts("");
    }
    return 0;
}