前言
这是评测记录
正题
AC评测记录链接:
https://www.luogu.org/record/show?rid=7945350
大意
一个图,没错要求不能走重复的边和点。求走最多次的情况下路最短。
解题思路
每次行走就是一个流量在流,然后将边权设为1就可以保证边只能走一次。之后就是点只能走一次,将一个点拆为入点和出点,连进来的连入点,连出去的连出点,然后之间连一条边权为1的边这样那个点就只能走一次了。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct line{int to,w,c,next;
}a[100081];
int tot,n,m,s,t,f[501],ls[501],tail,answer;
int state[501],x,y,w,c,ans,head,pre[501];
bool v[501];
void addl(int x,int y,int w,int c)
{a[++tot].to=y;a[tot].w=w;a[tot].c=c;a[tot].next=ls[x];ls[x]=tot;a[++tot].to=x;a[tot].w=0;a[tot].c=-c;a[tot].next=ls[y];ls[y]=tot;
}
bool spfa()
{for (int i=1;i<=t;i++)f[i]=2147483647;head=0;tail=1;v[s]=true;state[1]=s;f[s]=0;while (head!=tail){head=head%t+1;int x=state[head];for (int q=ls[x];q;q=a[q].next){int y=a[q].to;if (a[q].w&&f[x]+a[q].c<f[y]){f[y]=f[x]+a[q].c;pre[y]=q;if (!v[y]){v[y]=true;tail=tail%t+1;state[tail]=y;}}}v[x]=false;}if (f[t]==2147483647) return 0;else return 1;
}
void upway()
{int now;ans+=f[t];now=t;answer+=1;while (now!=s){a[pre[now]].w--;a[pre[now]^1].w++;now=a[pre[now]^1].to;}
}
int main()
{tot=1;scanf("%d%d",&n,&m);s=1;t=2*n;addl(s,2,2147483647,0);addl(t-1,t,2147483647,0);//起点和终点可以走无数遍for (int i=2;i<n;i++)addl(i*2-1,i*2,1,0);//连入点和出点for (int i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&c);addl(x*2,y*2-1,1,c);//连接}while (spfa()) upway();printf("%d %d",answer,ans);
}