旅行(圧縮された状態、古典的な巡回セールスマン問題)

非常に多くの日数コーディングした後、氏Acmerが良いrest.So走行が最良の選択であることを望む彼は訪問のn都市に決定しました!(彼はすべての都市を見に主張する!そして、彼は彼のために開始ステーションされた都市気にしませんスーパーマンは、最初はどの都市に彼をもたらすことができるが、一度だけ。)、そしてもちろんメートルの道路がここにあります、usual.But氏Acmerはそう簡単に彼は倍以上の都市を訪問する望んでいないことを飽きとしての手数料を以下の!そして、彼ので、彼は合計料金を最小限にするために望んでいることを意味している!彼はあなたが彼が助けをあなたになりsee.So怠け者です。

入力

いくつかのテストケースがありますが、最初の行は2 intergersのn(1 <= N <= 10)であり、m、彼が訪問する必要がある手段のn都市であり、彼が選択することができますメートルの道路、そしてメートルの線は、各行が意志に従うがあります3 intergersを、b及びc(1 <= B <= n)を含む、手段とBとコストとの間の道路は、ファイルの終わりに当然c.Inputのものです。

出力

出力彼が払うべきだと最低料金、または-1彼は、このようなルートを見つけることができない場合。

 

サンプル入力

2 1

1 2 100

3 2

1 2 40

2 3 50

3 3

1 2 3

1 3 4

2 3 10

サンプル出力

100

90

7

 

トピック効果:N市内観光へ行く人、彼はすべての都市から開始することができ、都市間メートルの道路があり、各道路のコストを行うのにかかる、すべての都市を解かれ、各都市が訪問2倍以下最小コスト

アイデア:私たちは、Xの都市の数、および都市のX数が訪問されている回数に行ったこと、および対応する最小コストの状況を試してみて、更新するために、他の都市に行ってきました現在の都市を開始点として、状態などの都市で現在していますこれらの都市の数がn次元の配列は明らかに非現実的で開く、それを格納する方法には、この状態になっているが、この時間は、私たちは、圧縮状態に適用することができエンコード考えました:

質問の数に合わせて3つだけの、訪問一度ありまし、二回があったので、三元数は、その後、都市の状態を保存し、Nビットの三つのことができますされていない各都市の尋ね番号システムは状態N都市を格納することができ、我々は、三元数X、都市のiは都市の数のI /(3 ^ I)%3 Xに等しい訪れ、そこでトリットビットと仮定します

したがって、我々は再帰式を締結することができます:

私にとっては男:DP [I] [J] =分(DP [I] [J]、DP [I-3 ^ J] [V] + [V] [j]をワット) 

全ての一つ:DP [I + 3 ^ V] =分(DP [I + 3 ^ V] [V]、DP [I] [j]はW [J] + [V])

 

この問題はmemsetのは、バイト単位で割り当てられ、memestと塗りつぶし機能の違いを忘れて、問題が発生してきた、私はINF = 999999を使用し始め、結果はとても1と0のための一般的な割り当てた場合、エラーにつながりました

コード付き:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define INF 0x3f    
#define check(x,y) (x/tab[y])%3   //获取状态X中,到达Y城市的次数 
using namespace std;
int tab[11]= {1},dp[60000][11];  //tab数组存储#3的次方数 
int main() {
	int n,m;
	for(int i=1; i<=10; i++) {   //初始化tab数组 
		tab[i]=tab[i-1]*3;
	}
	while(cin>>n>>m) {
		int w[11][11],cost=0x3f3f3f3f;
		memset(w,INF,sizeof(w));
		memset(dp,INF,sizeof(dp));     //初始化为无穷大 
		int x,y,wi;
		for(int i=0; i<m; i++) {
			cin>>x>>y>>wi;
			x--;
			y--;     //城市编号转化成 0开始 
			w[x][y]=w[y][x]=min(w[x][y],wi);
		}
		for(int i=0; i<n; i++)dp[tab[i]][i]=0;  //初始化从每个城市出发的情况,保证每种状态都能遍历到 
		for(int i=1; i<tab[n]; i++) {
			bool flag=true;   //设置标志flag,如果 i 状态下,去过了 n个城市,则可以尝试更新最小花费 
			for(int j=0;j<n;j++){
				
				if(check(i,j)==0){  
					flag=false;  //i 状态下 j 城市没有去过 
					continue;
				}
				for(int v=0;v<n;v++){
					if(check(i,v)==2)continue;  //如果 i 状态下 v城市已经访问了两次跳过 v 城市 
					dp[i+tab[v]][v]=min(dp[i+tab[v]][v],dp[i][j]+w[j][v]);  //我为人人递推 
				}
			}
			if(flag){  //0~n-1城市都有去过 
				for(int j=0;j<n;j++){
					cost=min(cost,dp[i][j]);  //尝试更新最小花费 
				}
			}
		}
		if(cost==0x3f3f3f3f)cost=-1;  //如果不能完成遍历所有城市的目标 
        cout<<cost<<endl;
       // printf("%d\n",cost);
	}
	return 0;
}

 

公開された42元の記事 ウォン称賛16 ビュー3400

おすすめ

転載: blog.csdn.net/qq_41542638/article/details/102704149