(紀中)1195. 最小總代價【狀壓DP】

時間限制: 1000 ms 空間限制: 131072 KB 具體限制
Goto ProblemSet


題目描述
nn個人在做傳遞物品的遊戲,編號爲1n1-n
遊戲規則是這樣的:開始時物品可以在任意一人手上,他可把物品傳遞給其他人中的任意一位;下一個人可以傳遞給未接過物品的任意一人。
即物品只能經過同一個人一次,而且每次傳遞過程都有一個代價;不同的人傳給不同的人的代價值之間沒有聯繫;
求當物品經過所有nn個人後,整個過程的總代價最小是多少。


輸入
第一行爲nn,表示共有nn個人16>=n>=2(16>=n>=2)
以下爲nnn*n的矩陣,第i+1i+1行、第j列表示物品從編號爲ii的人傳遞到編號爲jj的人所花費的代價,特別的有第i+1i+1行、第i列爲1-1(因爲物品不能自己傳給自己),其他數據均爲正整數(<=10000)(<=10000).
(對於5050%的數據,n<=11n<=11)。

輸出
一個數,爲最小的代價總和。


樣例輸入
2
-1 9794
2724 -1

樣例輸出
2724


數據範圍限制


提示
【限制】
50% n<=11


解題思路
思路:狀壓DP。。。(普及一下關於位運算的小知識~~.)

題目大意:有nn個人在傳球,可以從任意一個人開始,任何一個未接球的人,都可以作爲下一個接球的人,每兩個人之間傳球需要花費一些代價,問所有人都接到過球后的最小代價。
f[st][i]f[st][i]表示當前狀態爲st下,以i爲當前的最後接球人的最小代價。
初始狀態: f[1<<i][i]=0;f[1<<i][i]=0;表示一開始物品在i手中。

所有的狀態的區間爲1 (1<<n)11~(1<<n)-1
對於每一種狀態,由於每一個人都有可能作爲該狀態的最後持球人,所以我們要枚舉0 n10~n-1
當然必須這個人要是拿過球的,即(1<<j)&i)爲真
j作爲當前的最後持球人,他才能繼續往下傳,下一個接球的人顯然也必須有一個條件:他沒有接過球,即(1<<k)&i)爲假

狀態轉移方程:
f[i(1<<k)][k]=min(f[i(1<<k)][k],f[i][j]+a[j][k]);f[i∣(1<<k)][k]=min(f[i∣(1<<k)][k],f[i][j]+a[j][k]);

ii個狀態時,最後持球人爲j,將球傳給了kk,那麼新狀態爲i(1<<k)i|(1<<k),最後持球人變爲k。由於球從jj傳給了kk,顯然代價爲f[i][j]+a[j][k]f[i][j]+a[j][k]。那新狀態的最小代價是min(f[i][j]+a[j][k])min(f[i][j]+a[j][k])

傳球結束後,這個狀態(1<<n)1(1<<n)-1下,由於每個人都可以作最後持球人,所以還要進行一輪打擂臺minmin


代碼

#include<bits/stdc++.h>
using namespace std;
int n,f[1<<17][17],a[20][20],ans=2147483647;
int main(){
	scanf("%d",&n);
	memset(f,127/3,sizeof(f));
	for(int i=0;i<n;i++)
	for(int j=0;j<n;j++)
		scanf("%d",&a[i][j]);
	for(int i=0;i<n;i++) f[1<<i][i]=0;
	for(int i=1;i<(1<<n);i++)
	for(int j=0;j<n;j++)
		if((1<<j)&i) 
			for(int k=0;k<n;k++)
				if(!((1<<k)&i)) 
					f[i|(1<<k)][k]=min(f[i|(1<<k)][k],f[i][j]+a[j][k]);
	for(int i=0;i<n;i++) ans=min(ans,f[(1<<n)-1][i]);
	printf("%d",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章