Time Limit: 2000MS | Memory Limit: 20000K | |
Total Submissions: 9923 | Accepted: 2742 |
Description
Input
Output
Sample Input
3 1 3 1 1 0 1 1 1 0 1 1
Sample Output
12
犯了非常二的错误,导致WA到死。在求解最小割时用的是Maxflow(s, T),而我建的图应该是Maxflow(s, T+N)。醉了。。。
题意:给你N个点,又给出一个矩阵代表点与点之间的关系。若Map[i][j] = 1,表示i连j。现在问你最少去掉几个点使得S与T不连通,并输出字典序最小的方案.若无法使得S和T不连通,输出NO ANSWER!。
思路:
1,先拆点建图求解最小割ans;
2,枚举所有点i(i != S || i != T && 1 <= i <= N),删去点i后建新图跑一次最小割,得到新割tt。
若tt < ans,说明删去的点在割点集里面,记录并更新ans = tt。
反之说明该点不在割点集里面,复原该点,继续枚举下一个点。
因为我们每次都是贪心的选择编号较小的点入割点集,所以若最小割存在,在枚举完所有点后,就可以得到字典序最小的方案。
简单说下建图:
1,对于点i(i != S || i != T && 1 <= i <= N),建边i到i+N,容量为1;
2,对于点S和T,建边S->S+N和T->T+N,容量为无穷大;
3,对于可达关系<i, j>,建边i->j,容量为1。
注意:我的建图方案中源点是S,汇点是T+N。
AC代码:
#include <cstdio> #include <cstring> #include <queue> #include <stack> #include <vector> #include <algorithm> #define MAXN 500 #define MAXM 20000 #define INF 0x3f3f3f3f using namespace std; struct Edge { int from, to, cap, flow, next; }; Edge edge[MAXM]; int head[MAXN], edgenum; int dist[MAXN], cur[MAXN]; bool vis[MAXN]; int N, S, T; void init() { edgenum = 0; memset(head, -1, sizeof(head)); } void addEdge(int u, int v, int w) { Edge E1 = {u, v, w, 0, head[u]}; edge[edgenum] = E1; head[u] = edgenum++; Edge E2 = {v, u, 0, 0, head[v]}; edge[edgenum] = E2; head[v] = edgenum++; } int Map[201][201]; void input() { memset(Map, 0, sizeof(Map)); for(int i = 1; i <= N; i++) { for(int j = 1; j <= N; j++) scanf("%d", &Map[i][j]); } } bool BFS(int s, int t) { queue<int> Q; memset(dist, -1, sizeof(dist)); memset(vis, false, sizeof(vis)); dist[s] = 0; vis[s] = true; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i = head[u]; i != -1; i = edge[i].next) { Edge E = edge[i]; if(!vis[E.to] && E.cap > E.flow) { dist[E.to] = dist[u] + 1; if(E.to == t) return true; vis[E.to] = true; Q.push(E.to); } } } return false; } int DFS(int x, int a, int t) { if(x == t || a == 0) return a; int flow = 0, f; for(int &i = cur[x]; i != -1; i = edge[i].next) { Edge &E = edge[i]; if(dist[E.to] == dist[x] + 1 && (f = DFS(E.to, min(a, E.cap-E.flow), t)) > 0) { edge[i].flow += f; edge[i^1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } int Maxflow(int s, int t) { int flow = 0; while(BFS(s, t)) { memcpy(cur, head, sizeof(head)); flow += DFS(s, INF, t); } return flow; } void getMap() { init(); for(int i = 1; i <= N; i++) { for(int j = 1; j <= N; j++) { if(Map[i][j]) { if(i == j) { if(i == S || i == T) addEdge(i, i+N, INF); else addEdge(i, i+N, 1); } else addEdge(i+N, j, INF); } } } } int rec[MAXN];//记录要去掉的点集 int top; int temp[201][201]; void solve() { if(Map[S][T])//无法使得S和T不连通 { printf("NO ANSWER!\n"); return ; } getMap(); int ans = Maxflow(S, T+N);//最小割 if(ans == 0) { printf("0\n"); return ; } top = 0; for(int i = 1; i <= N; i++) { if(i == S || i == T) continue; for(int j = 1; j <= N; j++) { temp[i][j] = Map[i][j]; temp[j][i] = Map[j][i]; Map[i][j] = Map[j][i] = 0;//删点 } getMap(); int tt = Maxflow(S, T+N); if(tt < ans)//最小割减少 rec[top++] = i, ans = tt;//存储 else { for(int j = 1; j <= N; j++)//恢复 Map[i][j] = temp[i][j], Map[j][i] = temp[j][i]; } } printf("%d\n", top); for(int i = 0; i < top; i++) { if(i) printf(" "); printf("%d", rec[i]); } printf("\n"); } int main() { while(scanf("%d%d%d", &N, &S, &T) != EOF) { input(); solve(); } return 0; }