题目来源:http://showproblem.php?pid=3549
题意
给出一个网络,求最大流、。。。
思路
好像并没有什么思路,模板硬上,,,
刷了三道水题了,,终于可以去学学ISAP了。。。(好菜。。。欲哭无泪状。。。)
代码
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=19+10;
const int INF=0x3f3f3f3f;
int n,m;
int pre[maxn],f_l[maxn][maxn];
bool vis[maxn];
void init()
{
scanf("%d%d",&n,&m);
memset(f_l,0,sizeof(f_l));
while(m--)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
f_l[x][y]+=w;
}
}
bool bfs()
{
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
queue<int> Q;
Q.push(1);
vis[1]=1;
while(!Q.empty())
{
int u=Q.front();
Q.pop();
for(int v=1; v<=n; v++)
{
if(!vis[v]&&f_l[u][v])
{
pre[v]=u;
vis[v]=1;
if(v==n) return 1;
Q.push(v);
}
}
}
return 0;
}
void print_EK()
{
int maxflow=0;
while(bfs())
{
int tt=n,minn=INF;
while(tt!=1)
{
minn=min(f_l[pre[tt]][tt],minn);
tt=pre[tt];
}
maxflow+=minn;
tt=n;
while(tt!=1)
{
f_l[pre[tt]][tt]-=minn;
f_l[tt][pre[tt]]+=minn;
tt=pre[tt];
}
}
printf("%d\n",maxflow);
}
int main()
{
int T;
scanf("%d",&T);
for(int i=1;i<=T;i++)
{
init();
printf("Case %d: ",i);
print_EK();
}
return 0;
}
//ISAP优化
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1000+10;
//利用标高,寻找路径,并把边的序号记录在数组里,找到之后,进行操作。
struct pp
{
int v,nexx;
int flow,cap;
}edge[maxn<<1];
int first[maxn],h[maxn],num[maxn],cur[maxn],S[maxn];
//ISAP:邻接表+数组记录
int n,m,tot;
void ADD(int u,int v,int w)
{
edge[tot].v=v;
edge[tot].flow=0;
edge[tot].cap=w;
edge[tot].nexx=first[u];
first[u]=tot++;
}
void init(int i)
{
tot=0;
scanf("%d%d",&n,&m);
memset(first,-1,sizeof(first));
while(m--)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
ADD(u,v,w);
ADD(v,u,0);
}
printf("Case %d: ",i);
}
void height()
{
queue<int> Q;
while(!Q.empty()) Q.pop();
memset(h,-1,sizeof(h));
memset(num,0,sizeof(num));
Q.push(n);
h[n]=0;
++num[0];
while(!Q.empty())
{
int u=Q.front();
Q.pop();
for(int i=first[u];i!=-1;i=edge[i].nexx)
{
int v=edge[i].v;
if(h[v]==-1)
{
h[v]=h[u]+1;
Q.push(v);
num[h[v]]++;
}
}
}
}
void print_ISAP(int s,int t)
{
height();
int ans=0,top=0,u=s;
memcpy(cur,first,sizeof(first));
while(h[s]<n)
{
if(u==t)
{
int d=INF,pos;
for(int i=0;i<top;i++)
{
if(d>edge[S[i]].cap-edge[S[i]].flow)
{
d=edge[S[i]].cap-edge[S[i]].flow;
pos=i;
}
}
for(int i=0;i<top;i++)
{
edge[S[i]].flow+=d;
edge[S[i]^1].flow-=d;
}
top=pos;
ans+=d;
u=edge[S[top]^1].v;//回退点
continue;
}
int i=cur[u];//从下一条开始
for(;i!=-1;i=edge[i].nexx)
{
if(edge[i].cap>edge[i].flow&&h[u]==h[edge[i].v]+1)
{
cur[u]=i;
S[top++]=i;
u=edge[i].v;
break;
}
}
if(i==-1)
{
int d=n;//回退,重新标记高度
for(int i=first[u];i!=-1;i=edge[i].nexx)
{
if(edge[i].cap>edge[i].flow&&d>h[edge[i].v])
{
d=h[edge[i].v];
cur[u]=i;
}
}
if(--num[h[u]]==0) break;//如果当前高度的点只有一个,变化之后会出现断层。退出
++num[h[u]=d+1];
if(u!=s) u=edge[S[--top]^1].v;//回退到上一个
}
}
printf("%d\n",ans);
}
int main()
{
int T;
scanf("%d",&T);
for(int i=1;i<=T;i++)
{
init(i);
print_ISAP(1,n);
}
}