POJ 1815 Friendship(最小割+字典序输出割点)
2017-07-22 09:22
429 查看
http://poj.org/problem?id=1815
题意:
在现代社会,每个人都有自己的朋友。由于每个人都很忙,他们只通过电话联系。你可以假定A可以和B保持联系,当且仅当:①A知道B的电话号码;②A知道C的电话号码,而C能联系上B。如果A知道B的电话号码,则B也知道A的电话号码。
思路:
这题是要我们删点,既然是删点,那么就要拆点,容量就是1。
接下来凡是能联系的,就连边,容量为INF,因为我们不是要删除这些边。跑遍最大流就能算出至少要删除多少个点。
这道题的关键是要字典序顺序输出最小割的点集,在跑一遍最大流之后,我们按字典序顺序依次枚举每个点,将该点删除后然后再去跑最大流,如果流量减少了,说明它是割点。
题意:
在现代社会,每个人都有自己的朋友。由于每个人都很忙,他们只通过电话联系。你可以假定A可以和B保持联系,当且仅当:①A知道B的电话号码;②A知道C的电话号码,而C能联系上B。如果A知道B的电话号码,则B也知道A的电话号码。
思路:
这题是要我们删点,既然是删点,那么就要拆点,容量就是1。
接下来凡是能联系的,就连边,容量为INF,因为我们不是要删除这些边。跑遍最大流就能算出至少要删除多少个点。
这道题的关键是要字典序顺序输出最小割的点集,在跑一遍最大流之后,我们按字典序顺序依次枚举每个点,将该点删除后然后再去跑最大流,如果流量减少了,说明它是割点。
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<sstream> #include<vector> #include<stack> #include<queue> #include<cmath> #include<map> #include<set> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int INF = 0x3f3f3f3f; const int maxn = 20000 + 5; struct Edge { int from,to,cap,flow; Edge(int u,int v,int w,int f):from(u),to(v),cap(w),flow(f){} }; struct Dinic { int n,m,s,t; vector<Edge> edges; vector<int> G[maxn]; bool vis[maxn]; int cur[maxn]; int d[maxn]; void init(int n) { this->n=n; for(int i=0;i<n;++i) G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap) { edges.push_back( Edge(from,to,cap,0) ); edges.push_back( Edge(to,from,0,0) ); m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BFS() { queue<int> Q; memset(vis,0,sizeof(vis)); vis[s]=true; d[s]=0; Q.push(s); while(!Q.empty()) { int x=Q.front(); Q.pop(); for(int i=0;i<G[x].size();++i) { Edge& e=edges[G[x][i]]; if(!vis[e.to] && e.cap>e.flow) { vis[e.to]=true; d[e.to]=d[x]+1; Q.push(e.to); } } } return vis[t]; } int DFS(int x,int a) { if(x==t || a==0) return a; int flow=0, f; for(int &i=cur[x];i<G[x].size();++i) { Edge &e=edges[G[x][i]]; if(d[e.to]==d[x]+1 && (f=DFS(e.to,min(a,e.cap-e.flow) ) )>0) { e.flow +=f; edges[G[x][i]^1].flow -=f; flow +=f; a -=f; if(a==0) break; } } return flow; } int Maxflow(int s,int t) { this->s=s; this->t=t; int flow=0; while(BFS()) { memset(cur,0,sizeof(cur)); flow +=DFS(s,INF); } return flow; } }DC; int n,s,t; int mp[maxn][maxn]; int main() { //freopen("in.txt","r",stdin); while(~scanf("%d%d%d",&n,&s,&t)) { int dst=2*n+1; DC.init(dst+1); for(int i=1;i<=n;i++) { if(i==s || i==t) DC.AddEdge(i,i+n,INF); else DC.AddEdge(i,i+n,1); } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%d",&mp[i][j]); if(i==j) continue; if(mp[i][j]) DC.AddEdge(i+n,j,INF); } } if(mp[s][t]) {puts("NO ANSWER!");continue;} int cnt=DC.Maxflow(s,t); vector<int> ans; printf("%d\n",cnt); if(cnt==0) continue; for(int i=0;i<2*n;i+=2) //前2*n条边为每个顶点,依次枚举 { Edge& e=DC.edges[i]; if(e.from==s || e.from==t) continue; e.cap=0; //删边 for(int j=0;j<2*n;j++) DC.edges[j].flow = 0; int tmp=DC.Maxflow(s,t); //如果流量改变,说明这条边是割边 if(tmp<cnt) { cnt=tmp; ans.push_back(e.from); } else e.cap=1; if(cnt<=0) break; } for(int i=0;i<ans.size();i++) { printf("%d%c",ans[i],i==ans.size()-1?'\n':' '); } printf("\n"); } return 0; }
相关文章推荐
- poj 1815 Friendship 最小割 拆点 输出字典序
- POJ 1815 Friendship 最小割 + 字典序输出割点
- POJ 1815 Friendship 最小割 + 字典序输出割点
- poj--1815--Friendship(最小割点集)(枚举求最小字典序)
- poj 1815 Friendship 最小割输出最小方案
- POJ 1815 - Friendship 求最小割点..要求字典序...枚举+最小割
- POJ1815 Friendship(字典序最小最小割割边集)
- POJ 1815 Friendship(字典序最小最小割)
- poj 1815 Friendship 字典序最小+最小割
- poj 1815 Friendship 【最小割点集】【枚举删点 + 求解最小字典序】
- 【POJ1815】Friendship 网络流最小割
- Poj 1815 Friendship 枚举+求最小割
- poj 1815 Friendship (最小割+拆点+枚举)
- POJ 1815 Friendship ★(字典序最小点割集)
- poj 1815 Friendship (最小割+拆点+枚举)
- POJ 1815 Friendship ★(字典序最小点割集)
- POJ 1815 Friendship(最小割)
- POJ 1815 Friendship 最小割
- poj 2337 欧拉回路按照最小字典序输出+注意为了按最小字典序怎么处理邻接表
- poj 3693 Maximum repetition substring 重复次数最多的子串(若有多个 输出字典序最小的子串) 后缀数组 (DC3) (SA)