When good old friends are going|

run-away

园龄:1年7个月粉丝:1关注:0

2024-12-20 15:18阅读: 15评论: 0推荐: 0

「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 中国大陆许可协议进行许可。

posted @   run-away  阅读(15)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起