1. 程式人生 > >(狀壓dp)ABC 067 F : Mole and Abandoned Mine

(狀壓dp)ABC 067 F : Mole and Abandoned Mine

技術分享 cts using sub src oops bit live set

Mole decided to live in an abandoned mine. The structure of the mine is represented by a simple connected undirected graph which consists of N vertices numbered 1through N and M edges. The i-th edge connects Vertices ai and bi, and it costs ciyen (the currency of Japan) to remove it.

Mole would like to remove some of the edges so that there is exactly one path from Vertex 1

to Vertex N that does not visit the same vertex more than once. Find the minimum budget needed to achieve this.

Constraints

  • 2≤N≤15
  • N?1≤MN(N?1)?2
  • 1≤ai,biN
  • 1≤ci≤106
  • There are neither multiple edges nor self-loops in the given graph.
  • The given graph is connected.

Input

Input is given from Standard Input in the following format:

N M
a1 b1 c1
:
aM bM cM

Output

Print the answer.

Sample Input 1

4 6
1 2 100
3 1 100
2 4 100
4 3 100
1 4 100
3 2 100

Sample Output 1

200

By removing the two edges represented by the red dotted lines in the figure below, the objective can be achieved for a cost of 200 yen.

技術分享

Sample Input 2

2 1
1 2 1

Sample Output 2

0

It is possible that there is already only one path from Vertex 1 to Vertex N in the beginning.

Sample Input 3

15 22
8 13 33418
14 15 55849
7 10 15207
4 6 64328
6 9 86902
15 7 46978
8 14 53526
1 2 8720
14 12 37748
8 3 61543
6 5 32425
4 11 20932
3 12 55123
8 2 45333
9 12 77796
3 9 71922
12 15 70793
2 4 25485
11 6 1436
2 7 81563
7 11 97843
3 1 40491

Sample Output 3

133677

同時進行兩種遞推:1、加入單獨1點 2、加入一與當前無交集的點集    
get: line50 如何取得補集的所有子集。
 1 #include <bits/stdc++.h>
 2 typedef long long ll;
 3 using namespace std;
 4 const int MAX=1e5+5;
 5 const int INF=1e9;
 6 int n,m;
 7 int edge[20][20];
 8 int total;
 9 int cost[1<<16][16],dp[1<<16][16];//dp[s][x]記錄達到某點集s,最後“末端”(繼續連接其余點的唯一點)為x時余下權值和最大的邊的情況
10 int inner[1<<16];//內部的邊
11 int main()
12 {
13     scanf("%d%d",&n,&m);
14     for(int i=1;i<=m;i++)//讀入數據
15     {
16         int x,y,price;
17         scanf("%d%d%d",&x,&y,&price);
18         --x;--y;
19         edge[x][y]=edge[y][x]=price;
20     }
21     total=1<<n;
22     for(int i=0;i<total;i++)//計算某點集內部所有邊權值之和
23         for(int a=0;a<n;a++)
24             if(i&(1<<a))
25                 for(int b=0;b<a;b++)
26                     if(i&(1<<b))
27                         if(edge[a][b])
28                             inner[i]+=edge[a][b];
29     for(int i=0;i<total;i++)//計算某點集到點集外某點所有邊的權值之和
30         for(int a=0;a<n;a++)
31             if(!(i&(1<<a)))
32                 for(int b=0;b<n;b++)
33                     if((i&(1<<b))&&edge[a][b])
34                         cost[i][a]+=edge[a][b];
35     memset(dp,-1,sizeof(dp));
36     dp[1][0]=0;//只有1個點的集合dp值顯然為0
37     for(int i=0;i<total;i++)
38     {
39 
40         for(int a=0;a<n;a++)
41         {
42             if((i&(1<<a))&&dp[i][a]!=-1)
43             {
44                 for(int b=0;b<n;b++)
45                     if(!(i&(1<<b)))/*只加入一個點*/
46                         if(edge[a][b])
47                             dp[i|(1<<b)][b]=max(dp[i|(1<<b)][b],dp[i][a]+edge[a][b]);
48                 /*加入一個點集*/
49                 int left=total-1-i;
50                 for(int now=left;now!=0;now=(now-1)&left)//用此循環得到所有
51                 {
52                     int num=inner[now]+cost[now][a];
53                     dp[i|now][a]=max(dp[i|now][a],dp[i][a]+num);
54                 }
55             }
56         }
57     }
58     printf("%d\n",inner[total-1]-dp[total-1][n-1]);
59     return 0;
60 }

(狀壓dp)ABC 067 F : Mole and Abandoned Mine