洛谷/Acwing 电视网络 Cable TV Network
Acwing因为位置原因无法AC,洛谷上10ms就跑过了,ACwing说我超时,可能是玄学
另外,我们令S和T不联通,就要不允许删除S和T(拆点时边权为inf),而不能直接以s'为起点,t为终点,我无法证明这样做是正确的,也无法证明这样做是错的,而事实上他就是错的
教训是不要使用为证明的算法,而是采用已证明的,显然的算法
#include<queue>
#include<string>
#include<cstring>
#include<iostream>
//#pragma GCC optimize(3)
using namespace std;
#define go(i,a,b) for(int i=a;i<=b;++i)
#define com(i,a,b) for(int i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define add_e(u,v,w) add(u,v,w),add(v,u,0)
#define _new(x) (x+50)
#define min(a,b) (a<b?a:b)
const int inf=0x3f3f3f3f,N=500+10,M=60010;
int n,m,cnt,head[N*2],d[N*2],s,t,x[M],y[M];
queue<int>q;
struct edge{
int nxt,u,v,w;
}e[M];
void add(int u,int v,int w){
e[cnt]=(edge){head[u],u,v,w};
head[u]=cnt++;
}
inline void read(int &x){
x=0;char f=1,c=getchar();
while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); }
while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); }
x*=f;
}
bool bfs(){
mem(d,0);
while(!q.empty()) q.pop();
q.push(s);d[s]=1;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i+1;i=e[i].nxt){
int v=e[i].v;
if(!e[i].w||d[v]) continue;
d[v]=d[u]+1;
if(v==t) return 1;
q.push(v);
}
}
return 0;
}
int dinic(int u,int low){
if(u==t) return low;
int res=low,f;
for(int i=head[u];i+1&&res;i=e[i].nxt){
int v=e[i].v;
if(d[v]==d[u]+1&&e[i].w){
f=dinic(v,min(res,e[i].w));//这样就保证了res永远大于等于0
if(!f){
d[v]=0;continue;
}
e[i].w-=f;
e[i^1].w+=f;
res-=f;
}
}
return low-res;
}
int work(){
int ans=0;
while(bfs()){
ans+=dinic(s,inf);
}
return ans;
}
int main(){
//freopen("input.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(scanf("%d%d",&n,&m)==2){
mem(head,-1);cnt=0;
go(i,1,m) read(x[i]),read(y[i]),++x[i],++y[i];
getchar();
if(n==0){ puts("0"); continue; }
if(n==1){ puts("1"); continue; }
int ans=inf;
go(i,1,m)
add_e(_new(x[i]),y[i],inf),add_e(_new(y[i]),x[i],inf);
go(x,1,n)
add_e(x,_new(x),1);
go(i,1,n)
go(j,i+1,n){
s=_new(i),t=j;
ans=min(ans,work());
}
if(ans==inf) printf("%d\n",n);
else cout<<ans<<endl;
}
return 0;
}