「SP4227」 MSE06I
题意
给 \(n\) 个点,\(m\) 条边的有向图,除起点和终点,其他点都只能经过一次,求两条从起点到终点的路径使得长度和最小。
分析
从较小的数据范围,只能经过一次的限制可以想到使用网络流。
因为要求最短路径,可以使用费用流求解。
限制一个点经过次数的经典套路是拆点,把点 \(v\) 拆成左部点 \(v\) 和右部点 \(v'\),从 \(v\) 向 \(v'\) 连一条流量为 \(1\)、费用为 \(0\) 的边。
建立虚拟源点 \(s\)、汇点 \(t\),\(s\) 向每个左部点连流量为 \(+\infty\)、费用为 \(0\) 的边;每个右部点向 \(t\) 连流量为 \(+\infty\)、费用为 \(0\) 的边。
对于原图里 \(u\) 向 \(v\) 的一条边权为 \(w\) 的边,在新图里 \(u'\) 向 \(v\) 连一条流量为 \(1\)、费用为 \(w\) 的边。
最后从 \(s\) 跑到 \(t\) 的费用流,如果最大流不为 \(2\) 则无解,否则答案为最小费用。
Code
#include<bits/stdc++.h> typedef long long ll; using namespace std; #define dbg(x) cout<<#x<<": "<<x<<"\n" static char buf[1000000],*p1=buf,*p2=buf,obuf[1000000],*p3=obuf; #define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++ #define putchar(x) (p3-obuf<1000000)?(*p3++=x):(fwrite(obuf,p3-obuf,1,stdout),p3=obuf,*p3++=x) inline ll read(){ll x=0,f=1;char c=getchar();while(c<48||c>57){if(c==45)f=0;c=getchar();}while(c>47&&c<58)x=(x<<3)+(x<<1)+(c^48),c=getchar();return f?x:-x;} inline void write(ll x){if(!x){putchar(48);putchar('\n');return;}ll top=0,s[40];if(x<0)x=-x,putchar(45);while(x)s[top++]=x%10^48,x/=10;while(top--)putchar(s[top]);putchar('\n');} mt19937_64 rnd(chrono::system_clock::now().time_since_epoch().count()); const ll mod=1e9+7,maxn=1e5+5,maxt=505; ll n=read(),m=read(),timer=1,s,t,tot=1,head[maxn],dis[maxn],mn[maxn],prend[maxn],presz[maxn]; bool vis[maxn]; struct edge{ ll to,nxt,val,cost; }e[maxn]; inline void add(ll u,ll v,ll w,ll c){ e[++tot]=(edge){v,head[u],w,c}; head[u]=tot; e[++tot]=(edge){u,head[v],0,-c}; head[v]=tot; } inline bool spfa(){ for(ll i=s;i<=t;++i)dis[i]=INT_MAX;dis[s]=0; memset(vis,0,sizeof(vis)); queue<ll>q;q.push(s); vis[s]=1;mn[s]=INT_MAX; while(!q.empty()){ ll u=q.front();q.pop();vis[u]=0; for(ll i=head[u];i;i=e[i].nxt){ ll v=e[i].to,w=e[i].val,c=e[i].cost; if(w>0&&dis[u]+c<dis[v]){ dis[v]=dis[u]+c; mn[v]=min(mn[u],w); prend[v]=u,presz[v]=i; if(!vis[v]){ q.push(v);vis[v]=1; } } } } return dis[t]!=INT_MAX; } inline void solve(){ s=0,t=n*2+1;tot=1,memset(head,0,sizeof(head)); while(m--){ ll u=read()+1,v=read()+1,w=read(); add(u+n,v,1,w); } add(s,1,INT_MAX,0);add(n*2,t,INT_MAX,0); add(1,n+1,2,0),add(n,n*2,2,0); for(ll i=2;i<n;++i)add(i,n+i,1,0); ll mcost=0,mflow=0; while(spfa()){ ll u=t; while(u!=s){ ll v=prend[u],i=presz[u]; e[i].val-=mn[t],e[i^1].val+=mn[t]; u=v; } mcost+=dis[t]*mn[t]; mflow+=mn[t]; } if(mflow!=2)printf("Instance #%lld: Not possible\n",timer); else printf("Instance #%lld: %lld\n",timer,mcost); } signed main(){ while(n||m){ solve();++timer; n=read(),m=read(); } fwrite(obuf,p3-obuf,1,stdout); return 0; }
本文作者:run-away
本文链接:https://www.cnblogs.com/run-away/p/18619364
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
分类:
标签:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步