POJ2135 Farm Tour(网络流)
所有人!都过来!
【题目分析】
一开始完全没想到是网络流啊。。。。。。做了两次最短路发现有反例所以gg。
其实我觉得单源最短路可以算作网络流的特殊情况,所有连边容量为1,费用为w,建立超级源点s和超级汇点t,s向起点连容量为1费用为0的边,终点向t连容量为1费用为0的边,跑一遍最小费用最大流,最后的费用就是最短路长度。
回到这道题,因为要走个来回并且费用最少,所以将s与起点、t与终点的连边的容量设为2即可,方法还是同上。
【代码~】
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e3+10;
const int MAXM=2e4+10;
const int INF=0x3f3f3f3f;
int n,m,cnt,s,t,cost;
int head[MAXN],cur[MAXN],dis[MAXN],vis[MAXN],work[MAXN];
int nxt[MAXM],to[MAXM],w[MAXM],c[MAXM];
void Add(int u,int v,int f,int co)
{
nxt[cnt]=head[u];
head[u]=cnt;
to[cnt]=v;
w[cnt]=f;
c[cnt]=co;
cnt++;
}
void add(int x,int y,int z,int k)
{
Add(x,y,z,k);
Add(y,x,0,-k);
}
bool SPFA()
{
queue<int> q;
memset(dis,INF,sizeof(dis));
memset(work,0,sizeof(work));
vis[s]=1;
dis[s]=0;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=nxt[i])
{
int v=to[i];
if(dis[v]>dis[u]+c[i]&&w[i])
{
dis[v]=dis[u]+c[i];
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
return dis[t]<INF;
}
int dfs(int u,int dist)
{
if(u==t)
{
cost+=dist*dis[t];
return dist;
}
work[u]=1;
int res=0;
for(int i=head[u];i!=-1;i=nxt[i])
{
int v=to[i];
if(dis[v]==dis[u]+c[i]&&w[i]&&!work[v])
{
int di=dfs(v,min(w[i],dist-res));
if(di)
{
w[i]-=di;
w[i^1]+=di;
res+=di;
if(res==dist)
break;
}
}
}
return res;
}
int dinic()
{
int maxf=0;
while(SPFA())
maxf+=dfs(s,INF);
return cost;
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,1,z);
add(y,x,1,z);
}
s=0,t=n+1;
add(s,1,2,0);
add(n,t,2,0);
cout<<dinic()<<'\n';
return 0;
}