poj 1815 Friendship
分割点法は,1つの点を2つに分割し,間の流量を点の重み値とすることで,分割点を求める集合が分割辺を求める集合になる.
#include<iostream>
using namespace std;
const int maxn=405;
const int INF=0x7ffffff;
int c[maxn][maxn],dep[maxn],q[maxn],flow[maxn][maxn],num[maxn],pre[maxn];
void bfs(int n,int s,int t)
{
int f=0,r=0,u,v;
memset(dep,125,sizeof(dep));
memset(num,0,sizeof(num));
dep[t]=0;
num[0]++;
q[r++]=t;
while(f<r)
for(v=q[f++],u=1; u<=n;u++)
if(flow[u][v]<c[u][v] && dep[u]>n)
{
dep[u]=dep[v]+1;
q[r++]=u;
num[dep[u]]++;
}
}
int find_path(int n,int u)//
{
for(int i=1;i<=n;i++)
if(flow[u][i]<c[u][i]&&dep[u]==dep[i]+1)
return i;
return -1;
}
int relabel(int n,int u) // ,
{
int tmp=n;
for(int i=1;i<=n;i++)
if(flow[u][i]<c[u][i])// u 。。。
tmp=min(tmp,dep[i]+1); //
return tmp;
}
int sap(int n,int s,int t)
{
memset(pre,-1,sizeof(pre));
int u=s,max_flow=0,cost,x,v,k;
bfs(n,s,t);
while(dep[s]<n) //
{
v=find_path(n,u);// i
if(v>=0)
{
pre[v]=u;
u=v;
if(v==t)//
{
cost=INF;
for(k=t; k!=s; k=pre[k])
cost=min(cost,c[pre[k]][k]-flow[pre[k]][k]);
for(k=t;k!=s; k=pre[k])
flow[pre[k]][k] += cost,flow[k][pre[k]] -=cost;
max_flow += cost;
u=s; //
}
}
else //
{
x=relabel(n,u); //
num[x]++;num[dep[u]]--; //
if(num[dep[u]]==0) //
return max_flow;
dep[u]=x;
if(pre[u]!=s)
u=pre[u];
}
}
return max_flow;
}
int main()
{
int n,s,t,i,j,w;
bool flag=0;
cin>>n>>s>>t;
s=s+n; //
for(i=1;i<=n;i++)
{
c[i][i+n]=1;
for(j=1;j<=n;j++)
{
scanf("%d",&w);
if(w)
{
if(i==s-n&&j==t)
flag=true; //s t;
c[i+n][j]=INF;
}
}
}
if(flag)
{
printf("NO ANSWER!
");
return 0;
}
int max_flow,cur_flow,ans[205],cnt;
max_flow = sap(n*2,s,t);
cnt=0;
for(i=1;i<=n;i++) // ,
{
if(i==s-n||i==t) continue;
memset(flow,0,sizeof(flow));
c[i][i+n]=0; // ,
cur_flow = sap(2*n,s,t);
if(cur_flow<max_flow) // , i
{
ans[cnt++]=i;
max_flow--; //
}
else
c[i][i+n]=1; //
if(max_flow<=0)
break;
}
cout<<cnt<<endl;
for(i=0;i<cnt;i++)
printf("%d ",ans[i]);
cout<<endl;
system("pause");
return 0;
}