POJ 3084 最小割 Panic Room
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一把锁。。。
用矩阵和链表都写了一下
代码(矩阵):
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<queue> #define inf 9999999 #define Min(a,b)a<b?a:b using namespace std; int map[25][25],level[25]; int n,t; int dfs(int x,int cap) { if(x==t)return cap; int temp=cap,i; for(i=0;i<=n;i++) { if(level[i]==level[x]+1&&temp>0&&map[x][i]>0) { int tt=dfs(i,Min(temp,map[x][i])); map[x][i]-=tt; map[i][x]+=tt; temp-=tt; } } return cap-temp; } int bfs() { queue<int>qu; memset(level,-1,sizeof(level)); qu.push(n); level[n]=0; int i; while(!qu.empty()) { int tt=qu.front(); qu.pop(); for(i=0;i<=n;i++) { if(level[i]==-1&&map[tt][i]>0) { level[i]=level[tt]+1; qu.push(i); } } } if(level[t]!=-1)return 1; return 0; } int dinic() { int SUM=0; while(bfs()) { SUM+=dfs(n,inf); } return SUM; } int main() { int i,CASE,k,num; char ch[5]; scanf("%d",&CASE); while(CASE--) { memset(map,0,sizeof(map)); scanf("%d%d",&n,&t);//t为汇点 for(k=0;k<n;k++) { // cin>>ch; scanf("%s",ch); if(ch[0]=='I') map[n][k]=inf;//n为源点!! scanf("%d",&num); while(num--) { scanf("%d",&i); map[k][i]=inf; map[i][k]++;//注意重边 } } int ans=dinic(); if(ans<inf) printf("%d\n",ans); else printf("PANIC ROOM BREACH\n"); } return 0; }
(二)
#include<iostream> #include<string> #include<cstring> #include<cstdio> #include<queue> #define inf 9999999 #define Min(a,b)a<b?a:b using namespace std; int head[25],level[25]; int n,t,s_edge; struct Edge { int to,w,next; }edge[1102];//开始开小了 写的450(20*20),拜托,边还要翻倍呢 Runtime Error了次 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].next=head[u]; head[u]=s_edge; s_edge++; edge[s_edge].to=u; edge[s_edge].w=w2; edge[s_edge].next=head[v]; head[v]=s_edge; return ; } int dfs(int x,int cap) { if(x==t)return cap; int temp=cap; for(int i=head[x];i;i=edge[i].next) { int To=edge[i].to; if(level[To]==level[x]+1&&edge[i].w>0&&temp>0) { int tt=dfs(To,Min(edge[i].w,temp)); edge[i].w-=tt; edge[i^1].w+=tt; temp-=tt; } } return cap-temp; } int bfs() { int i; memset(level,-1,sizeof(level)); queue<int>qu; level[n]=0; qu.push(n); while(!qu.empty()) { int tt=qu.front(); qu.pop(); for(i=head[tt];i;i=edge[i].next) { 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); } return SUM; } int main() { int CASE; char ch[5]; int num,i,k; scanf("%d",&CASE); while(CASE--) { scanf("%d%d",&n,&t); s_edge=1; memset(head,0,sizeof(head)); for(i=0;i<n;i++) { scanf("%s",ch); //开始改了N小时,没想到 定义ch时 写的 int ch[5] 真无语。。。 if(ch[0]=='I') { addedge(n,i,inf,0);//n为源点 } scanf("%d",&num); while(num--) { scanf("%d",&k); addedge(i,k,inf,1); } } int ans=dinic(); if(ans<inf) printf("%d\n",ans); else printf("PANIC ROOM BREACH\n"); } return 0; }