HDU 3001 Travelling 狀態壓縮dp+3進位,hdudp
題意:一個人要旅行,他要去n個地方,且這n個地方每個地方最多可以走2次;
給m條路徑,尋問最短花費
很明顯的狀態壓縮,但是要求每個點最多隻能走兩次,就沒辦法標記當前點走過或是沒走過,只能用三進位來表示
1代表地點1被走過一次、
2代表地點1被走過兩次、
3(即10)代表地點2被走過一次、
4(即11)代表地點1被走過一次,地點2被走過一次、
5(即12)代表地點1被走過兩次,地點2被走過一次、
附AC代碼
#include<stdio.h>#include<string.h>int dis[15],dp[80000][15],dpp[80000][15];int map[15][15];int min1(int a,int b){if(a<b)return a;return b;}int main(){int i,j,n,m,k;j=1;for(i=1;i<=11;i++){dis[i]=j;j*=3;}for(i=0;i<dis[11];i++){k=i;for(j=1;j<=11;j++){dpp[i][j]=k%3;k/=3;}}while(scanf("%d%d",&n,&m)!=EOF){int sum;memset(map,127,sizeof(map));sum=map[0][0];int cnt=map[0][0];while(m--){scanf("%d%d%d",&i,&j,&k);if(k<map[i][j])//重邊 map[j][i]=map[i][j]=k;}memset(dp,127,sizeof(dp));for(i=1;i<=n;i++){dp[dis[i]][i]=0;//}for(k=0;k<dis[n+1];k++){int tot=1;for(i=1;i<=n;i++){if(dpp[k][i]==0) tot=0;if(dp[k][i]==cnt)continue;for(j=1;j<=n;j++){if(i==j)continue;//相同的地點不用更新 if(dpp[k][j]>=2)continue;//兩次不用更新,因為不能再走了 if(map[i][j]==cnt)continue;//map[i][j]==cnt表示沒有從i到j的路故不用更新 int l=k+dis[j];dp[l][j]=min1(dp[l][j],dp[k][i]+map[i][j]);}}if(tot){for(i=1;i<=n;i++){sum=min1(sum,dp[k][i]);}}}if(sum==cnt)sum=-1;printf("%d\n",sum);}return 0; }