BZOJ2324: [ZJOI2011]營救皮卡丘
Description
皮卡丘被火箭隊用邪惡的計謀搶走了!這三個壞家夥還給小智留下了赤果果的挑釁!為了皮卡丘,也為了正義,小智和他的朋友們義不容辭的踏上了營救皮卡丘的道路。
火箭隊一共有N個據點,據點之間存在M條雙向道路。據點分別從1到N標號。小智一行K人從真新鎮出發,營救被困在N號據點的皮卡丘。為了方便起見,我們將真新鎮視為0號據點,一開始K個人都在0號點。
由於火箭隊的重重布防,要想摧毀K號據點,必須按照順序先摧毀1到K-1號據點,並且,如果K-1號據點沒有被摧毀,由於防禦的連鎖性,小智一行任何一個人進入據點K,都會被發現,並產生嚴重後果。因此,在K-1號據點被摧毀之前,任何人是不能夠經過
為了簡化問題,我們忽略戰鬥環節,小智一行任何一個人經過K號據點即認為K號據點被摧毀。被摧毀的據點依然是可以被經過的。
K個人是可以分頭行動的,只要有任何一個人在K-1號據點被摧毀之後,經過K號據點,K號據點就被摧毀了。顯然的,只要N號據點被摧毀,皮卡丘就得救了。
野外的道路是不安全的,因此小智一行希望在摧毀N號據點救出皮卡丘的同時,使得K個人所經過的道路的長度總和最少。
請你幫助小智設計一個最佳的營救方案吧!
Input
第一行包含三個正整數N,M,K。表示一共有N+1個據點,分別從0到N編號,以及M條無向邊。一開始小智一行共K個人均位於0號點。
接下來M行,每行三個非負整數,第i行的整數為Ai,Bi,Li。表示存在一條從Ai號據點到Bi號據點的長度為Li的道路。
Output
僅包含一個整數S,為營救皮卡丘所需要經過的最小的道路總和。
Sample Input
3 4 20 1 1
1 2 1
2 3 100
0 3 1
Sample Output
3【樣例說明】
小智和小霞一起前去營救皮卡丘。在最優方案中,小智先從真新鎮前往1號點,接著前往2號據點。當小智成功摧毀2號據點之後,小霞從真新鎮出發直接前往3號據點,救出皮卡丘。
HINT
對於100%的數據滿足N ≤ 150, M ≤ 20 000, 1 ≤ K ≤ 10, Li ≤ 10 000, 保證小智一行一定能夠救出皮卡丘。至於為什麽K ≤ 10,你可以認為最終在小智的號召下,小智,小霞,小剛,小建,小遙,小勝,小光,艾莉絲,天桐,還有去日本旅遊的黑貓警長,一同前去大戰火箭隊。
題目傳送門
做完這道題我都有點迷糊,神tm我網絡流什麽時候做了將近40道了。。。
不會做啊,去%了發題解
首先floyd一遍每個點對的最小距離,控制一下前面的點對都被訪問過,這裏有個正確性我不會證
先給建圖在解釋:
1.S->0’ 流量K費用0
2.i’->j 流量1費用dis[i][j]
3.S->i’ 流量1費用0
4.i->T 流量1費用0
第一條和第二條我不講了,這都不會左轉天臺
這道題我們要保證訪問的每一個點都要被炸掉,所以這大概就叫有下界無上界
感覺還是有點不懂,先挖個坑吧
代碼如下:
#include<cmath> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; typedef long long ll; struct node { int x,y,next,other; ll c,d; }a[2100000];int len,last[2100000]; int INF=1<<29; void ins(int x,int y,ll c,ll d) { int k1,k2; k1=++len; a[len].x=x;a[len].y=y;a[len].c=c;a[len].d=d; a[len].next=last[x];last[x]=len; k2=++len; a[len].x=y;a[len].y=x;a[len].c=0;a[len].d=-d; a[len].next=last[y];last[y]=len; a[k1].other=k2; a[k2].other=k1; } bool v[210000]; ll ans; int st,ed,head,tail,pre[210000]; ll cc[210000],list[210000],d[210000]; bool SPFA() { for(int i=0;i<=ed;i++)d[i]=INF; d[st]=0; memset(v,false,sizeof(v));v[st]=true; memset(cc,0,sizeof(cc));cc[st]=INF; list[1]=st;head=1;tail=2; while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(a[k].c>0&&d[y]>d[x]+a[k].d) { d[y]=d[x]+a[k].d; pre[y]=k; cc[y]=min(cc[x],a[k].c); if(!v[y]) { v[y]=true; list[tail++]=y; } } } head++; v[x]=false; } if(d[ed]==INF)return false; ans+=d[ed]*cc[ed]; int x=ed; while(x!=0) { int k=pre[x]; a[k].c-=cc[ed];a[a[k].other].c+=cc[ed]; x=a[k].x; } return true; } int dd[210][210]; int n,m,K; int main() { scanf("%d%d%d",&n,&m,&K);st=n*2+2;ed=n*2+3; len=0;memset(last,0,sizeof(last)); for(int i=1;i<=n;i++)dd[i][i]=0; for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) if(i!=j) dd[i][j]=INF; for(int i=1;i<=m;i++) { int x,y,c; scanf("%d%d%d",&x,&y,&c); dd[x][y]=dd[y][x]=min(dd[x][y],c); } for(int k=0;k<=n;k++) for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) if(k<=i||k<=j) dd[i][j]=min(dd[i][j],dd[i][k]+dd[k][j]); for(int i=1;i<=n;i++) { ins(st,i+n+1,1,0); ins(i,ed,1,0); } ins(st,n+1,K,0); for(int i=0;i<=n;i++) for(int j=i+1;j<=n;j++) if(dd[i][j]!=INF) ins(i+n+1,j,1,dd[i][j]); ans=0; while(SPFA()==true){} printf("%lld\n",ans); return 0; }
by_lmy
BZOJ2324: [ZJOI2011]營救皮卡丘