(狀壓dp)ABC 067 F : Mole and Abandoned Mine
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
Constraints
- 2≤N≤15
- N?1≤M≤N(N?1)?2
- 1≤ai,bi≤N
- 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