非常非常裸的题目-但还是想了好久
“点上有权值的题目可以考虑拆点解决–刘汝佳”
记住这句话可以说非常有用,一开始还考虑到点边互换上去了。
有两个注意点:
1. 不用枚举所有点对,确定一个点之后,对于冥冥中确定但不知道在哪里的最小割点集,另外的点都可以分为这个点一边的和另一边的,枚举一圈就好了。
2. 源点取拆出来的入度点,汇点取拆出来的出度点,因为默认源汇点不需要被删去。这样源汇点无法割开的话,流量为INF。
#include<bits/stdc++.h>
using namespace std;
const int maxv = 110;
const int INF = 0x3fffffff;
struct edge{
int to, cap, rev;
edge(int t=0, int c=0, int r=0){
to = t; cap = c; rev = r;
}
};
vector<edge> G[maxv];
int level[maxv];
int iter[maxv];
void add_edge(int from, int to, int cap){
G[from].push_back(edge( to, cap, G[to].size()));
G[to].push_back(edge(from, 0, G[from].size()-1));
}
void bfs(int s){
memset(level, -1, sizeof(level));
queue<int> que;
level[s] = 0;
que.push(s);
while (!que.empty()){
int v = que.front(); que.pop();
for (int i = 0; i < G[v].size(); i++){
edge &e = G[v][i];
if (e.cap > 0 && level[e.to] < 0){
level[e.to] = level[v] + 1;
que.push(e.to);
}
}
}
}
int dfs(int v,int t,int f){
if (v == t) return f;
for (int &i = iter[v]; i < G[v].size(); i++){
edge &e = G[v][i];
if (e.cap > 0 && level[v] < level[e.to]){
int d = dfs(e.to, t, min(f, e.cap));
if (d > 0){
e.cap -= d;
G[e.to][e.rev].cap += d;
return d;
}
}
}
return 0;
}
int maxflow(int s,int t){
int flow = 0;
while (1){
bfs(s);
if (level[t] < 0) return flow;
memset(iter, 0, sizeof(iter));
int f;
while ((f = dfs(s, t, INF))>0){
flow += f;
}
}
}
int n,m;
int u[5500];
int v[5500];
string s;
int main(){
while(~scanf("%d%d",&n,&m)){
//cout<<s<<endl;
for(int i=0;i<m;i++){
scanf(" (%d,%d)",&u[i],&v[i]);
}
int ans = INF;
for(int k=1;k<n;k++){
for(int i=0;i<2*n;i++) G[i].clear();
for(int i=0;i<n;i++) add_edge(i,i+n,1);
for(int i=0;i<m;i++) add_edge(u[i]+n,v[i],INF),add_edge(v[i]+n,u[i],INF);
ans = min(ans,maxflow(n,k));
//printf("%d\n",ans);
}
if(ans == INF){
if(n*(n-1)/2==m) printf("%d\n",n);
else printf("0\n");
}
else printf("%d\n",ans);
}
return 0;
}