刷題總結——支線劇情(bzoj3876費用流)
阿新 • • 發佈:2017-09-05
inpu 代碼 電視劇 pac ring 新的遊戲 mat tar algorithm
輸入一行包含一個正整數N。
接下來N行,第i行為i號劇情點的信息;
第一個整數為,接下來個整數對,Bij和Tij,表示從劇情點i可以前往劇
情點,並且觀看這段支線劇情需要花費的時間。
2 2 1 3 2
2 4 3 5 4
2 5 5 6 6
0
0
0
對於100%的數據滿足N<=300,0<=Ki<=50,1<=Tij<=300,Sigma(Ki)<=5000
題目:
【故事背景】 宅男JYY非常喜歡玩RPG遊戲,比如仙劍,軒轅劍等等。不過JYY喜歡的並不是戰鬥場景,而是類似電視劇一般的充滿恩怨情仇的劇情。這些遊戲往往 都有很多的支線劇情,現在JYY想花費最少的時間看完所有的支線劇情。 【問題描述】 JYY現在所玩的RPG遊戲中,一共有N個劇情點,由1到N編號,第i個劇情點可以根據JYY的不同的選擇,而經過不同的支線劇情,前往Ki種不同的新的劇情點。當然如果為0,則說明i號劇情點是遊戲的一個結局了。 JYY觀看一個支線劇情需要一定的時間。JYY一開始處在1號劇情點,也就是遊戲的開始。顯然任何一個劇情點都是從1號劇情點可達的。此外,隨著遊戲的進行,劇情是不可逆的。所以遊戲保證從任意劇情點出發,都不能再回到這個劇情點。由於JYY過度使用修改器,導致遊戲的“存檔”和“讀檔”功能損壞了, 所以JYY要想回到之前的劇情點,唯一的方法就是退出當前遊戲,並開始新的遊戲,也就是回到1號劇情點。JYY可以在任何時刻退出遊戲並重新開始。不斷開始新的遊戲重復觀看已經看過的劇情是很痛苦,JYY希望花費最少的時間,看完所有不同的支線劇情。Input
Output
輸出一行包含一個整數,表示JYY看完所有支線劇情所需要的最少時間。
Sample Input
62 2 1 3 2
2 4 3 5 4
2 5 5 6 6
0
0
0
Sample Output
24HINT
JYY需要重新開始3次遊戲,加上一開始的一次遊戲,4次遊戲的進程是
1->2->4,1->2->5,1->3->5和1->3->6。
題解:
這道題很NB····
表面看起來如果直接按題意建圖的話,會是一道有下界費用流的題···md我不會···
但可以轉成普通費用流的題····這裏引用PoPoQQQ題解····%%%%%%
對於每一條邊權為z的邊x->y:
從S到y連一條費用為z,流量為1的邊 代表這條邊至少走一次
從x到y連一條費用為z,流量為INF的邊 代表這條邊除了至少走的一次之外還可以隨便走
對於每個點x:
從x到T連一條費用為0,流量為x的出度的邊
從x到1連一條費用為0,流量為INF的邊,代替原圖上的源和匯
不得不說想到這樣建圖實在是太巧妙了·····
代碼:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> #include<cctype> #include<cstring> #include<string> #include<algorithm> #include<queue> using namespace std; const int inf=1e+8; const int N=5000; const int M=150005; queue<int>que; int tot=1,first[N],go[M],next[M],rest[M],cost[M]; int chu[N],ans=0,dis[N],src,des,n; bool insta[N],visit[N]; int R() { char c; int f=0; for(c=getchar();c<‘0‘||c>‘9‘;c=getchar()); for(;c>=‘0‘&&c<=‘9‘;c=getchar()) f=(f<<3)+(f<<1)+c-‘0‘; return f; } inline void comb(int a,int b,int c,int d) { next[++tot]=first[a],first[a]=tot,go[tot]=b,rest[tot]=c,cost[tot]=d; next[++tot]=first[b],first[b]=tot,go[tot]=a,rest[tot]=0,cost[tot]=-d; } inline bool SPFA() { for(int i=src;i<=des;i++) visit[i]=false,dis[i]=inf; que.push(src); dis[src]=0; while(!que.empty()) { int u=que.front(); que.pop(); insta[u]=false; for(int e=first[u];e;e=next[e]) { int v=go[e]; if((dis[v]>dis[u]+cost[e])&&rest[e]) { dis[v]=dis[u]+cost[e]; if(!insta[v]) { que.push(v); insta[v]=true; } } } } return dis[des]!=inf; } inline int dinic(int u,int flow) { if(u==des) { ans+=flow*dis[des]; return flow; } visit[u]=true; int res=0,delta,v; for(int e=first[u];e;e=next[e]) { if(dis[v=go[e]]==dis[u]+cost[e]&&!visit[v]&&rest[e]) { delta=dinic(v,min(rest[e],flow-res)); if(delta) { rest[e]-=delta; rest[e^1]+=delta; res+=delta; if(res==flow) break; } } } return res; } inline void maxflow() { while(SPFA()) dinic(src,inf); } int main() { //freopen("a.in","r",stdin); n=R(); int t,a,b; src=0,des=n+1; for(int i=1;i<=n;i++) { t=R(); for(int j=1;j<=t;j++) { a=R(),b=R(); comb(src,a,1,b); comb(i,a,inf,b); } chu[i]=t; } for(int i=1;i<=n;i++) { comb(i,des,chu[i],0); if(i!=1) comb(i,1,inf,0); } maxflow(); cout<<ans<<endl; return 0; }
刷題總結——支線劇情(bzoj3876費用流)