平面图的最小割转最短路(点非常多)

来源:互联网 发布:鹰卫浴淘宝 编辑:程序博客网 时间:2024/04/29 10:05


1170: 一网打尽

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 57  Solved: 13
[Submit][Status][Web Board]

Description

        一天关押危险犯人的监狱突然爆炸了,里面的犯人都逃了出来。这些犯人以前都是一个犯罪团伙的,他们都要逃到他们的老巢!这可万万不得了!
         警方立即动员起来,派出警察来拦截他们。
         如图:
整个地图是一个网格图形,坐标(x,y)表示第x行的第y个点。监狱在左上角,犯人的老巢在右下角。左上角点为(1,1),右下角点(N,M),上图中(N=3,M=4)。有两种类型的道路,1:(x,y)->(x+1,y);2:(x,y)->(x,y+1)。图上的权值表示这条道路上最多能通过的犯人数目。
         现在警方要派人埋伏在这些道路上伏击,为了不遗漏任何一个逃犯,如果一条道路上最多通过K个犯人,同样也要派出K个警察,才能完全封锁这条道路。请帮助警方安排一个伏击方案,使派出的警察数量最少,且抓到所有犯人。

Input

第一行为一个整数T,表示测试数据的组数
接下来个给出T组测试数据,对于每组测试数据:
第一行为两个正整数N,M(2<=N,M<=1000)表示网格大小
接下来分两部分,这两部分用一个空行隔开
第一部分:
共N-1行,每行M个数,表示纵向道路的最多允许通过犯人数目
即:第x行的第y个数表示是边(x,y)->(x,y+1)上的最多允许通过犯人数目
第二部分:
共N行,每行M-1个数,表示横向道路的最多允许通过犯人数目
即:第x行的第y个数表示是边(x,y)->(x+1,y)上的最多允许通过犯人数目
 
数据保证边上的权值小于1000。数据的大小不超过10M

Output

对每组测试数据,输出一个整数,表示参与伏击的警察的最少数目

Sample Input

13 43 4 1 85 2 4 95 10 16 1 32 3 10

Sample Output

6

典型的平面图的最小割转最短路,找到平面图的对偶图,然后在图上跑一遍最短路就是这个平面图的最小割。关于对偶图就不多说了- -,百度一大堆。(平面图就是任意两条边不想交- - 在平面就能画出来的图)


/**************************************************************    User: error408    Language: C/C++    School: SSDUT    Saying: Do one thing at a time,and do well.****************************************************************/#include <iostream>#include <vector>#include <map>#include <set>#include <queue>#include <stack>#include <algorithm>#include <cstdio>#include <string>#include <cstring>#include <cmath>#include <ctime>using namespace std;#pragma comment(linker,"/STACK:102400000,102400000") /// kuo zhan#define clr(s,x) memset((s),(x),sizeof(s))#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define lowbit(x) (x&(-x))#define PB push_back#define For(i,a,b) for(int i=a;i<b;i++)#define FOR(i,a,b) for(int i=a;i<=b;i++)#define RL(N) scanf("%I64d",&N)#define RLL(L,R) (RL(L),RL(R))typedef long long               LL;typedef unsigned int            uint;typedef unsigned long long      ULL;typedef vector<int>             vint;typedef vector<string>          vstring;void RI (int& x){    x = 0;    char c = getchar ();    while (c == ' '||c == '\n')    c = getchar ();    bool flag = 1;    if (c == '-'){        flag = 0;        c = getchar ();    }    while (c >= '0' && c <= '9'){        x = x * 10 + c - '0';        c = getchar ();    }    if (!flag)    x = -x;}void RII (int& x, int& y){RI (x), RI (y);}void RIII (int& x, int& y, int& z){RI (x), RI (y), RI (z);}/************************************END DEFINE*********************************************/const int maxn = 1e6 + 1000;const int maxm = 4e6 + 1000;const int inf  = 0x7fffffff;struct Side{    int to,next,w;}side[maxm];int n,m,T,s,e,cnt;int top,node[maxn];inline void add_side(int u,int v,int c){    side[top]=(Side){v,node[u],c};    node[u]=top++;    side[top]=(Side){u,node[v],c};    node[v]=top++;}bool inque[maxn];int dis[maxn];int q[maxn];int spfa(){    int head,tail;    head = tail = 0;    for(int i=0;i<cnt;i++){        dis[i]=inf;        inque[i]=false;    }    dis[s]=0;    q[tail++]=s;    while(head!=tail){        int u=q[head++];        head%=maxn;        inque[u]=false;        for(int i=node[u];i!=-1;i=side[i].next){            int v=side[i].to;            if(dis[u]+side[i].w<dis[v]){                dis[v]=dis[u]+side[i].w;                if(!inque[v]){                    inque[v]=true;                    q[tail++]=v;                    tail%=maxn;                }            }        }    }    return dis[e];}void init(){    top = 0;    clr(node,-1);}int main(){    scanf("%d",&T);    while(T--){        init();        scanf("%d%d",&n,&m);        s = (n-1)*(m-1);        e = (n-1)*(m-1)+1;        cnt = (n-1)*(m-1)+2;        int w;        for(int i=0;i<n-1;i++){            scanf("%d",&w);            add_side(e,i*(m-1),w);            for(int j=1;j<m-1;j++){                scanf("%d",&w);                add_side(i*(m-1)+j,i*(m-1)+j-1,w);            }            scanf("%d",&w);            add_side(s,i*(m-1)+m-2,w);        }        for(int j=0;j<m-1;j++){            scanf("%d",&w);            add_side(j,s,w);        }        for(int i=1;i<n-1;i++)        for(int j=0;j<m-1;j++){            scanf("%d",&w);            add_side(i*(m-1)+j,(i-1)*(m-1)+j,w);        }        for(int j=0;j<m-1;j++){            scanf("%d",&w);            add_side(e,(n-2)*(m-1)+j,w);        }        printf("%d\n",spfa());    }    return 0;}


0 0