题意:n个点,m条边,n<=1e3,m<=1e4 问从1出发到达n,在从n回到1并且每条边经过一次的最短路径?
贪心:从1到n找最短路在把路径反向 在从n到1找最短路,非常容易举出反例(样例即可)该贪心是错误的.
因为边为无向边 所以可以转换成求出两条1~n的路径 并且这两条路径无公共边 路径之和最短
建图:每条边流量为1,费用为长度.上面问题就等价于,求从1~n流量为2的最小费用流
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <cstdio>
using namespace std;
const int N=2e5+20;
const int inf=2e8;
int n,m;
int head[N],num;
struct node{
int to,next,vol,cost;
}e[4*N];
void insert(int u,int v,int vol,int cost)
{
e[num].to=v,e[num].vol=vol,e[num].cost=cost;
e[num].next=head[u],head[u]=num++;
e[num].to=u,e[num].vol=0,e[num].cost=-cost;//反向边 减少流量,则价格也减少
e[num].next=head[v];
head[v]=num++;
}
int inq[N],dist[N],pre[N],path[N];
queue<int> q;
bool SPFA(int s,int t)
{
while(!q.empty())
q.pop();
memset(pre,-1,sizeof(pre));
memset(dist,0x7f,sizeof(dist));
memset(inq,0,sizeof(inq));
inq[s]=1,dist[s]=0,q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop(),inq[u]=0;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(e[i].vol>0&&dist[v]>dist[u]+e[i].cost)
{
dist[v]=dist[u]+e[i].cost;
pre[v]=u,path[v]=i;//前一个点和边
if(!inq[v])
inq[v]=1,q.push(v);
}
}
}
if(pre[t]==-1)
return false;
return true;
}
int Min_CostFlow(int s,int t,int F)
{
int cost=0,flow=0;
while(SPFA(s,t))
{
if(flow==F)//
break;
int f=inf;
for(int u=t;u!=s;u=pre[u])
f=min(f,e[path[u]].vol);//path[u],u的前一条边
flow+=f,cost+=dist[t]*f;
for(int u=t;u!=s;u=pre[u])
{
e[path[u]].vol-=f;
e[path[u]^1].vol+=f;//残余网络
}
}
return cost;
}
int main()
{
while(cin>>n>>m)
{
int u,v,w;
num=0;
memset(head,-1,sizeof(head));
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&w);
insert(u,v,1,w);
insert(v,u,1,w);
}
int ans=Min_CostFlow(1,n,2);
cout<<ans<<endl;
}
return 0;
}