[2018.3.30集训]path-对偶图-最小割
題目大意
給出一個包含 n + 1 個結點的有向圖,結點的編號為 0 到 n。圖中有 m 條
有向邊,第 i 條有向邊起點為 ui,終點為 vi,且長度為 wi。并且這些邊還滿
足如下的性質:
? 對任意一條邊,滿足 ui < vi。
? 不存在兩條邊 i; j 使得 ui < uj < vi < vj。
除了結點 0 和結點 n 以外,其余的每個結點都有顏色。現在需要你找出一條從結點 0 走到結點 n 的最短路徑。對于任意一種顏色,這條路徑要么經過了這種顏色的所有結點,要么就不經過這種顏色的任意一個結點。如果不存在這樣的路徑,請輸出 -1,否則輸出最短路徑的長度。
題解
考場上對偶圖都想到了卻不會建限制邊QAQ
首先,平面圖最小割可以轉對偶圖最短路。
所以反過來也可以。
于是首先轉成對偶圖最小割建圖,每條邊在對偶后成為連接它在原圖兩側的兩個平面對偶后的點的邊。
接下來就是考慮限制了。
考慮對每種顏色建一個節點,對于一條邊,從它對偶后指向的節點,向它所覆蓋的所有邊的起點的顏色的節點連雙向$Inf$邊。
這么連的含義是,選擇了這條邊就不能選擇這種顏色。
于是,由于不選擇這種顏色,就需要對于每一種以該顏色為起點的邊,割掉完全覆蓋掉它的某一條邊。
于是,雙向$Inf$邊保證了上述條件,使得所有覆蓋了該顏色的邊的邊由于該顏色的節點而互相聯通,必須要一起割。
最后,對于那些只能到達$0$和$n$中的一個的節點,將它們的顏色的點向匯點連雙向$Inf$邊,代表這種顏色不能選。
于是就完成了!
代碼:
#include<bits/stdc++.h> using namespace std;inline int read() {int x=0;char ch=getchar();while(ch<'0' || '9'<ch)ch=getchar();while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();return x; }const int N=1009;struct ed {int u,v,w;bool cover;bool operator < (ed o)const{return v-u<o.v-o.u;} };int n,m,s,t,c[N],fl[N],Inf,tot; int g[N][N],id[N],rid[N]; bool cover[N],connect[N]; ed e[N*N];namespace flow {const int P=2009;const int M=100009;int to[M<<1],nxt[M<<1],w[M<<1],beg[P],tote=1;int q[P],dis[P];inline void add(int u,int v,int uc,int vc){to[++tote]=v;nxt[tote]=beg[u];w[tote]=uc;beg[u]=tote;to[++tote]=u;nxt[tote]=beg[v];w[tote]=vc;beg[v]=tote;}inline bool bfs(){memset(dis,0,sizeof(dis));q[1]=s;dis[s]=1;for(int l=1,r=1,u=q[1];l<=r;u=q[++l])for(int i=beg[u];i;i=nxt[i])if(w[i]>0 && !dis[to[i]])dis[to[i]]=dis[u]+1,q[++r]=to[i];return dis[t];}inline int dfs(int u,int flow){if(u==t || !flow)return flow;int cost=0;for(int i=beg[u],f;i;i=nxt[i])if(w[i]>0 && dis[to[i]]==dis[u]+1){f=dfs(to[i],min(flow-cost,w[i]));w[i]-=f;w[i^1]+=f;cost+=f;if(cost==flow)break;}if(!cost)dis[u]=-1;return cost;}inline int dinic(){int ret=0;while(bfs() && ret<Inf)ret+=dfs(s,Inf);return ret<Inf?ret:-1;} }using namespace flow;int main() {freopen("path.in","r",stdin);freopen("path.out","w",stdout);memset(g,127,sizeof(g));Inf=g[0][0]+1;n=read();m=read();for(int i=1;i<n;i++)c[i]=read();for(int i=1,u,v;i<=m;i++){u=read();v=read();g[u][v]=g[v][u]=min(g[u][v],read());}fl[n]=1;for(int i=n;i>=0;i--)for(int j=i+1;j<=n;j++)fl[i]|=(fl[j] && g[i][j]<Inf);m=0;for(int i=0;i<=n;i++)if(fl[i]){rid[id[i]=++m]=i;for(int j=0;j<i;j++)if(g[j][i]<Inf && id[j] && id[j]!=m-1)e[++tot]=(ed){id[j],m,g[j][i],0};}if(id[n]!=m)return puts("-1"),0;e[++tot]=(ed){1,m,0,0};sort(e+1,e+tot+1);for(int i=1;i<=tot;i++)printf("%d:%d %d %d\n",i,e[i].u,e[i].v,e[i].w);s=tot,t=tot+n+1;for(int i=1;i<=n-1;i++)if(fl[i])add(tot+c[i],t,Inf,Inf);for(int i=1;i<=tot;i++){for(int j=1;j<i;j++)if(!e[j].cover && e[i].u<=e[j].u && e[j].v<=e[i].v)e[j].cover=1,add(i,j,e[j].w,Inf);for(int j=e[i].u+1;j<=e[i].v-1;j++)if(!cover[j])cover[j]=1,add(i,tot+c[rid[j]],Inf,Inf);for(int j=e[i].u;j<e[i].v;j++)if(!connect[j])connect[j]=1,add(i,t,g[rid[j]][rid[j+1]],0);}printf("s %d\n",dinic());return 0; }轉載于:https://www.cnblogs.com/zltttt/p/8711609.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的[2018.3.30集训]path-对偶图-最小割的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [51nod]1284 2 3 5 7的
- 下一篇: 【面向对象设计与构造】第一次博客作业