poj 3084 最小割 模板题 PANIC ROOM

来源:互联网 发布:淘宝上心悦会员怎么刷 编辑:程序博客网 时间:2024/05/21 09:46

多校出了道模板题,于是就开始找模板。这题也是求最小割。

http://poj.org/problem?id=3084

题意:有n个房间,要确保一个房间(t)不能进坏人。相邻的房间可能会有门,但是门上的锁是单向的(只能从一个房间打开进入另一个房间,
a b ,只能从a进入b 不能从b 进入a),初始所有的锁都是开着的,问至少关上几个锁,才能不让坏人进入那个房间。
最小割?此前看到过最大流最小割定理,还以为是最大流的另一种求法呢,原来是用最大流的算法解决最小割问题。。。
构图还是关键:增加一个源点,不能进入坏人的房间(t)是汇点,如果某房间里本来有坏人,就连接这个房间和源点,
权值为inf,如果a->b想通,则a->b的权值为inf ,b->a权值为1(因为锁的控制权在a房间,如果坏人在a房间,这个门是
关不住的(inf),但是坏人如果在b房间,关上这个门只需锁一把锁(1),
还有就是重边问题,因为可能a->b一把锁,b->a一把锁。。。

这个模板是dfs的,估计不是很好。又找了个不是dfs的,还没来得及敲,又去搞代班的事了。

dfs的dinic:

#include <iostream>#include <cstring>#include <cstdio>#include <queue>#define inf 9999999#define Min(a,b) a < b ? a : busing namespace std;int head[25],level[25];int n,t,s_edge;struct Edge{    int to,w,nxt;}edge[1102];void addedge(int u, int v, int w1, int w2){    s_edge++;    edge[s_edge] .to = v;    edge[s_edge].w = w1;    edge[s_edge].nxt = head[u];    head[u] = s_edge;    s_edge++;    edge[s_edge].to = u;    edge[s_edge].w = w2;    edge[s_edge].nxt = head[v];    head[v] = s_edge;}int dfs(int x, int cap){ //n inf    if(x == t) return cap;    int tmp = cap;    for(int i = head[x]; i != -1; i = edge[i].nxt){        int to = edge[i].to;        if(level[to] == level[x] + 1 && edge[i].w > 0 && tmp > 0){            int tt = dfs(to,Min(edge[i].w,tmp));            edge[i].w -= tt;            edge[i ^ 1].w += tt;            tmp -= tt;        }    }    return cap - tmp;}int bfs(){    int i;    memset(level,-1,sizeof(level));    queue<int > qu;    level[n] = 0;//源点n是第0层    qu.push(n);//让源点进去    while(!qu.empty()){        int tt = qu.front(); qu.pop();        for(i = head[tt]; i != -1; i = edge[i].nxt){            int to = edge[i].to;            if(level[to] == -1 && edge[i].w > 0){                level[to] = level[tt] + 1;                qu.push(to);            }        }    }    if(level[t] != -1) return 1;    return 0;}int dinic(){    int sum = 0;    while(bfs()){        sum += dfs(n,inf);//源点 inf 。。。暂时的理解    }    return sum;}int main(){    int ca ; char ch[5];    int num,k;    scanf("%d",&ca);    while(ca --){        scanf("%d%d",&n,&t);        s_edge = 1;        memset(head,-1,sizeof(head));        for(int i = 0; i < n; i ++){            scanf("%s",ch);            if(ch[0] == 'I')                addedge(n,i,inf,0);//n为源点 源点到有入侵者的点连个无穷大(锁不住),有入侵者的点到源点连个0(不需要锁)            scanf("%d",&num);            while(num --){                scanf("%d",&k);                addedge(i,k,inf,1);//i 到 k 锁不住, k 到 i 需要一把锁            }        }        int ans = dinic();        if(ans < inf) //???            printf("%d\n",ans);        else            printf("PANIC ROOM BREACH\n");    }    return 0;}

不是dfs的dinic:

#include<iostream>#include<cstdio>#include<string>using namespace std;#define inf 1<<30#define cc(m,v) memset(m,v,sizeof(m))struct node{    int u,v,f,next;}edge[1000];int head[30],p=0,lev[30],cur[30];int que[1000];void ainit(){    p=0,cc(head,-1);}bool bfs(int s,int t){    int i,u,v,qin=0,qout=0;    cc(lev,0),lev[s]=1,que[qin++]=s;    while(qout!=qin){        u=que[qout++];        for(i=head[u];i!=-1;i=edge[i].next)            if(edge[i].f>0 && lev[v=edge[i].v]==0){                lev[v]=lev[u]+1,que[qin++]=v;                if(v==t) return 1;            }    }    return lev[t];}int dinic(int s,int t){    int qin=0,i,k,u,f;    int flow=0;    while(bfs(s,t)){        memcpy(cur,head,sizeof(head));        u=s,qin=0;        while(1){            if(u==t){                for(k=0,f=inf;k<qin;k++)                    if(edge[que[k]].f<f)                        f=edge[que[i=k]].f;                for(k=0;k<qin;k++)                    edge[que[k]].f-=f,edge[que[k]^1].f+=f;                flow+=f,u=edge[que[qin=i]].u;            }            for(i=cur[u];cur[u]!=-1;i=cur[u]=edge[cur[u]].next)                if(edge[i].f>0 && lev[u]+1==lev[edge[i].v]) break;            if(cur[u]!=-1)                que[qin++]=cur[u],u=edge[cur[u]].v;            else{                if(qin==0) break;                lev[u]=-1,u=edge[que[--qin]].u;            }        }    }    return flow;}void addedge(int u,int v){    edge[p].u=u,edge[p].v=v,edge[p].f=inf,edge[p].next=head[u],head[u]=p++;    edge[p].u=v,edge[p].v=u,edge[p].f=1,edge[p].next=head[v],head[v]=p++;}int main(){    int cas,n,m,u,i,s,t;    bool flag=0;    char as[5];    scanf("%d",&cas);    while(cas--){        ainit();        scanf("%d%d",&n,&t);        for(flag=0,i=0,s=n;i<n;i++){            scanf("%s%d",as,&m);            if(as[0]=='I'){                addedge(s,i);                while(m--){                    scanf("%d",&u);                    if(u==t) flag=1;                    addedge(i,u);                }            }else{                while(m--){                    scanf("%d",&u);                    addedge(i,u);                }            }        }        if(flag){            cout<<"PANIC ROOM BREACH"<<endl;continue;        }        int flo=dinic(s,t);        if(flo>=inf){            cout<<"PANIC ROOM BREACH"<<endl;continue;        }        printf("%d\n",flo);    }    return 0;}