lightoj 1061 KM 二分圖匹配

來源:互聯網
上載者:User

/*
    KM  二分圖匹配    MCMF   DP  搜尋   好題
    題意:在8*8棋盤上,給出8個皇后的初始位置,要求移動這8個皇后使得皇后之間互不攻擊。皇后移動一步可以沿直線或對角線移動任意個格子,但不>能跨過一個原本有皇后的格,即會被有皇后的格擋住。皇后的攻擊方式跟移動方式一樣的。    問最小移動總步數。

    思路:neko最初給我看的時候我第一反應是狀壓DP,但感覺很複雜,搞不動。
          他說只要能證明一個結論,這道題就很簡單了。要證:存在一種最終布局,使得最優移動過程中任何有皇后不互擋,也就是說我們可以不用考慮“不能跨皇后”這個限制,直接“穿越”做。
          我畫了個4*4的圖,然後幸運地得出了證明:假設現在在i點的皇后要到k點去(那k點當然是最終布局的皇后點啦,不然到那裡去幹嘛),中間有個j(j點有個皇后)隔住了。 那麼k與j就在一條直線上,也就是說 j 不是最終皇后點,那麼 j 就應該要挪到她相應的點去,等她挪完後就不擋住i 到達 k 點了。

          證了上述結論就好辦了,用二分圖帶權匹配KM演算法或者最大流最小費用流MCMF都可以做,費用為移動步數。
          我是用KM 做的。先預先處理出8*8上所有合理布局,一共92種。然後對於每種合理布局,拿來跟初始布局搞二分圖帶權匹配。易知這個二分圖是完
全二分圖(表述不太準確,就是X部Y部兩兩有邊)。

          這道題是歸類在DP上的 orz... 在vj上有人用搜尋+dp做... 
*/

//lightoj 1061

#include <limits.h>#include <stdio.h>#include <algorithm>#include <string.h>using namespace std;#define     N       8#define     ABS(x)      ((x) > 0 ? (x) : (-(x)))//bool flag = false;  //for debugint l[3][N*2], X[N], map[100][N], a[N][2];              //map[i][x] 存第i種合理布局的x行皇后應該放的列數int edge[N][N], LX[N], LY[N], link[N], slack[N];bool visx[N], visy[N];int Top = 0;void label(int row, int col){    l[0][col] ^= 1;    l[1][row+col] ^= 1;    l[2][row-col+N] ^= 1;}bool check(int row, int col){    return l[0][col] && l[1][row+col] && l[2][row-col+N];}void init(int row){    if(row == N) {        for(int i = 0; i < N; i++) map[Top][i] = X[i];        Top++;        return ;    }    for(int i = 0; i < N; i++) {        if(check(row, i)) {            X[row] = i;            label(row, i);            init(row+1);            label(row, i);        }    }}inline char rdc() { scanf(" "); return getchar(); }void read_board(){    int k = 0;    for(int i = 0; i < N; i++)        for(int j = 0; j < N; j++)            if(rdc() == 'q') a[k][0] = i, a[k][1] = j, k++;}int dis(int x1, int y1, int x2, int y2){    if(x1 == x2 && y1 == y2) return 0;    if(x1 == x2 || y1 == y2) return 1;    if(x1 + y1 == x2 + y2 || (x1 - y1) == (x2 - y2)) return 1;      //妹的,本來寫的是對的,看了neko的,然後改錯了=_=    return 2;}void build(int * map) {    for(int i = 0; i < N; i++) {        int x = a[i][0], y = a[i][1];        for(int j = 0; j < N; j++) {            edge[i][j] = -dis(x, y, j, map[j]);        }    }}bool find(int u){    visx[u] = true;    for(int v = 0; v < N; v++) if(!visy[v]) {        int rest = LX[u] + LY[v] - edge[u][v];        if(rest == 0) {            visy[v] = true;            if(link[v] == -1 || find(link[v])) {                link[v] = u;                return true;            }        } else slack[v] = min(slack[v], rest);    }    return false;}int KM(){    memset(LX, 128, sizeof(LX));    memset(LY,   0, sizeof(LY));    memset(link,-1, sizeof(link));    for(int i = 0; i < N; i++) for(int j = 0; j < N; j++) LX[i] = max(LX[i], edge[i][j]);    for(int start = 0; start < N; start ++) {        for(int i = 0; i < N; i++) slack[i] = (INT_MAX);        while(true) {            memset(visx, false, sizeof(visx));            memset(visy, false, sizeof(visy));            if(find(start)) break;            else {                int d = (INT_MAX);                for(int i = 0; i < N; i++) if(!visy[i]) d = min(d, slack[i]);                //if(d == (INT_MAX)) return -1;                for(int i = 0; i < N; i++) if(visx[i]) LX[i] -= d;                for(int i = 0; i < N; i++)                    if(visy[i]) LY[i] += d;                    else slack[i] -= d;            }        }    }    int sum = 0;    for(int i = 0; i < N; i++) sum += edge[link[i]][i];    return -sum;}int main(){    int cases, Cas = 0;    for(int i = 0; i < 3; i++) for(int j = 0; j < 2*N; j++) l[i][j] = 1;    init(0);    scanf("%d", &cases);    while(cases--) {        read_board();        int ans = 17;        for(int i = 0; i < Top; i++) {                  //枚舉每一種最終布局            build(map[i]);            //if(KM() == 6 && ans != 6) {            //    for(int j = 0; j < N; j++) printf("(%d,%d)  ", a[j][0]+1,a[j][1]+1);            //    printf("\n");            //    for(int j = 0; j < N; j++) printf("(%d,%d)  ", j+1, 1+map[i][j]);            //    printf("\n");            //}            ans = min(ans, KM());        }        printf("Case %d: %d\n", ++Cas, ans);    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.