1. 程式人生 > >BZOJ1001 [Beijing2006] 狼抓兔子

BZOJ1001 [Beijing2006] 狼抓兔子

相關資料:

根據最大流-最小割定理,一個網路中,兩個邊緣點之間的最大流等於最小割(最小割就是用一條割線將兩個點分割在兩個圖中,令刪去的邊的總權值最小。因此我們可以建圖,將每個圖(在本題中是每個三角形)作為一個點,點與點之間的連線就等於它們穿過的那條線的權值。在起點和終點間連一條線,線的內部和外部分別建立兩個點,將這兩個點和相鄰的三角形連線,然後刪去這條邊在整個圖中求最短路即可。

程式碼: (ps:當時也是在學習的過程中,所以借鑑了別人的程式碼)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>

using namespace std;

const int N=2000006, INF=0x3fffffff, E=N*3;

struct ARC {
    int u, val, next;
    inline void init(int a, int b, int c) {
        u=a, val=b, next=c;
    }
} arc[E];
int head[N], tot, S, T, n, m, dis[N];
bool vs[N];

inline void add_arc(int s, int t, int val) {
    arc[tot].init(t, val, head[s]);
    head[s]=tot++;
}

void SPFA(){
     queue<int> q;
     fill(dis, dis+T+1, INF);
     fill(vs, vs+T+1, 0);
     q.push(S);
     dis[S]=S,vs[S]=true;
     while (!q.empty()){
           int c=q.front(),i;
           q.pop();vs[c]=false;
           for (i=head[c]; i!=-1; i=arc[i].next){
               if (dis[c]+arc[i].val<dis[arc[i].u]){
                  dis[arc[i].u]=dis[c]+arc[i].val;
                  if (!vs[arc[i].u]){
                     q.push(arc[i].u);
                     vs[arc[i].u]=true;
                  }
               }
           }
     }
     printf("%d",dis[T]);
}

void read(int &x) {
    char c;
    while((c=getchar())<'0' || c>'9');
    x=c-'0';
    while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}

void Input() {//讀入
    for(int i=0, id1, id2, a; i<=n-1; i++)//讀入相鄰橫邊
        for(int j=1; j<=m-1; j++) {
            read(a);
            id1=((i-1)*(m-1)+j)*2-1;
            id2=(i*(m-1)+j)*2;//從1圖通往2圖
            if(i==0) id1=T,add_arc(id2, id1, a);
            else if(i==n-1) id2=S,add_arc(id2, id1, a);
            else add_arc(id1, id2, a),add_arc(id2, id1, a);
        }//增邊

    for(int i=1, id1, id2, a; i<=n-1; i++)
        for(int j=0; j<m; j++) {
            read(a);
            id1=((i-1)*(m-1)+j)*2;
            id2=((i-1)*(m-1)+j+1)*2-1;
            if(j==0) id1=S,add_arc(id1, id2, a);
            else if(j==m-1) id2=T,add_arc(id1, id2, a);
            else add_arc(id1, id2, a),add_arc(id2, id1, a);
        }

    for(int i=1, id1, id2, a; i<=n-1; i++)
        for(int j=1; j<=m-1; j++) {
            read(a);
            id1=((i-1)*(m-1)+j)*2;
            id2=((i-1)*(m-1)+j)*2-1;
            add_arc(id1, id2, a);
            add_arc(id2, id1, a);
        }
}

int main() {
    freopen("1001.in","r",stdin);
    freopen("1001.out","w",stdout);
    read(n), read(m);//讀入整數
    S=0, T=(n-1)*(m-1)*2+1;//S是源點T是匯點
    fill(head, head+T+1, -1), tot=0;//初始化為全-1
    if(n==1 || m==1) {//處理特殊情況
        if(n>m) swap(n, m);
        int ans=INF;
        for(int i=1, a; i<m; i++) {
            read(a);
            if(ans>a) ans=a;
        }
        printf("%d\n", ans==INF?0:ans);
    }
    else Input(), SPFA();
    return 0;
}

//BZOJ 1001

ps誰告訴我為什麼程式碼片點確定沒反應qwqwq