hdu 3311 steiner tree / 状态压缩spfa
http://acm.hdu.edu.cn/showproblem.php?pid=3311
给定6个基础点,和1000个辅助点,以及无向边若干。
求一棵代价最小的生成子树,使得6个基础点连通。
http://en.wikipedia.org/wiki/Steiner_tree_problem
方法一:
状态DP。
一棵树,实际上可以看成是由两棵子树拼接而成,或者一棵树扩展一条边筛选。而要完整地表示一棵子树,需要记录它的根,和对6个基础点的覆盖状态。
这样求一棵大树,可以枚举接合点,以及两个子树的覆盖状态。
若dp[i][j],i表示接合点,j表示覆盖状态,那么dp[i][j]=min{dp[i][k]+dp[i][j^k]}。
直接扩展一条边, 可以在保持j不变的情况下, 优先队列广搜, 大大降低复杂度.
方法二:
spfa。
dp[i][j]意义同上。一个点(i,j),对每个邻接点i',枚举那一头的状态j',然后用dp[i][j]+dp[i'][j']+way[i][i']去更新dp[i][j|j']和dp[i'][j|j']。
ps. topcoder srm 470 div1 level3是此题升级版.
1
#include
<
string
>
2 #include < vector >
3 #include < list >
4 #include < map >
5 #include < queue >
6 #include < stack >
7 #include < set >
8 #include < iostream >
9 #include < sstream >
10 #include < numeric >
11 #include < algorithm >
12 #include < cmath >
13 #include < cctype >
14 #include < cstdlib >
15 #include < cstdio >
16 #include < cstring >
17 using namespace std;
18
19 #define CLR(x) memset((x),0,sizeof(x))
20 #define SET(x,y) memset((x),(y),sizeof(x))
21 #define REP(i,x) for(int i=0;i<(x);i++)
22 #define FOR(i,x,y) for(int i=(x);i<(y);i++)
23 #define VI vector<int>
24 #define PB(i,x) (i).push_back(x)
25 #define MP(x,y) make_pair((x),(y))
26
27 struct EDGE{
28 int v,e,d;
29 }edg[ 20000 ];
30 int ecnt, gg[ 1006 ];
31
32 struct HEAP{
33 int v,d;
34 void set ( int nv, int nd){v = nv;d = nd;}
35 }hp[ 1006 * ( 1 << 6 ) * 10 ];
36 int sz;
37 bool vis[ 1006 ];
38
39 int dp[ 1006 ][ 1 << 6 ];
40 int N, M, P;
41
42 bool cmp( const HEAP & a, const HEAP & b)
43 { return a.d > b.d; }
44
45 void addedge( int u, int v, int d)
46 {
47 edg[ecnt].v = v; edg[ecnt].d = d; edg[ecnt].e = gg[u]; gg[u] = ecnt ++ ;
48 edg[ecnt].v = u; edg[ecnt].d = d; edg[ecnt].e = gg[v]; gg[v] = ecnt ++ ;
49 }
50
51 int steiner()
52 {
53 int up = 1 << (N + 1 );
54 SET(dp, - 1 );
55 REP(i,N + 1 ) dp[i][ 1 << i] = 0 ;
56 FOR(i,N + 1 ,N + M + 1 ) dp[i][ 0 ] = 0 ;
57 REP(i,up){
58 REP(j,N + M + 1 ){
59 for ( int k = i; k > 0 ; k = (k - 1 ) & i){
60 if (dp[j][k] !=- 1 && dp[j][i ^ k] !=- 1 )
61 if (dp[j][i] ==- 1 || dp[j][i] > dp[j][k] + dp[j][i ^ k])
62 dp[j][i] = dp[j][k] + dp[j][i ^ k];
63 }
64 }
65 sz = 0 ;
66 CLR(vis);
67 REP(j,N + M + 1 ) if (dp[j][i] !=- 1 ){
68 hp[sz ++ ]. set (j,dp[j][i]);
69 push_heap(hp, hp + sz, cmp);
70 }
71 while (sz){
72 int now = hp[ 0 ].v;
73 pop_heap(hp, hp + sz -- ,cmp);
74 if (vis[now]) continue ;
75 vis[now] = true ;
76 for ( int e = gg[now]; ~ e; e = edg[e].e){
77 int to = edg[e].v, td = dp[now][i] + edg[e].d;
78 if (dp[to][i] ==- 1 || dp[to][i] > td){
79 dp[to][i] = td;
80 hp[sz ++ ]. set (to,td);
81 push_heap(hp, hp + sz, cmp);
82 }
83 }
84 }
85 }
86 return dp[ 0 ][up - 1 ];
87 }
88
89 int main()
90 {
91 while ( ~ scanf( " %d %d %d " , & N, & M, & P)){
92 int u, v, d;
93 SET(gg, - 1 ); ecnt = 0 ;
94 REP(i,N + M){
95 scanf( " %d " , & d);
96 addedge( 0 ,i + 1 , d);
97 }
98 REP(i,P){
99 scanf( " %d %d %d " , & u, & v, & d);
100 addedge(u,v,d);
101 }
102 int ret = steiner();
103 printf( " %d\n " , ret);
104 }
105 return 0 ;
106 }
2 #include < vector >
3 #include < list >
4 #include < map >
5 #include < queue >
6 #include < stack >
7 #include < set >
8 #include < iostream >
9 #include < sstream >
10 #include < numeric >
11 #include < algorithm >
12 #include < cmath >
13 #include < cctype >
14 #include < cstdlib >
15 #include < cstdio >
16 #include < cstring >
17 using namespace std;
18
19 #define CLR(x) memset((x),0,sizeof(x))
20 #define SET(x,y) memset((x),(y),sizeof(x))
21 #define REP(i,x) for(int i=0;i<(x);i++)
22 #define FOR(i,x,y) for(int i=(x);i<(y);i++)
23 #define VI vector<int>
24 #define PB(i,x) (i).push_back(x)
25 #define MP(x,y) make_pair((x),(y))
26
27 struct EDGE{
28 int v,e,d;
29 }edg[ 20000 ];
30 int ecnt, gg[ 1006 ];
31
32 struct HEAP{
33 int v,d;
34 void set ( int nv, int nd){v = nv;d = nd;}
35 }hp[ 1006 * ( 1 << 6 ) * 10 ];
36 int sz;
37 bool vis[ 1006 ];
38
39 int dp[ 1006 ][ 1 << 6 ];
40 int N, M, P;
41
42 bool cmp( const HEAP & a, const HEAP & b)
43 { return a.d > b.d; }
44
45 void addedge( int u, int v, int d)
46 {
47 edg[ecnt].v = v; edg[ecnt].d = d; edg[ecnt].e = gg[u]; gg[u] = ecnt ++ ;
48 edg[ecnt].v = u; edg[ecnt].d = d; edg[ecnt].e = gg[v]; gg[v] = ecnt ++ ;
49 }
50
51 int steiner()
52 {
53 int up = 1 << (N + 1 );
54 SET(dp, - 1 );
55 REP(i,N + 1 ) dp[i][ 1 << i] = 0 ;
56 FOR(i,N + 1 ,N + M + 1 ) dp[i][ 0 ] = 0 ;
57 REP(i,up){
58 REP(j,N + M + 1 ){
59 for ( int k = i; k > 0 ; k = (k - 1 ) & i){
60 if (dp[j][k] !=- 1 && dp[j][i ^ k] !=- 1 )
61 if (dp[j][i] ==- 1 || dp[j][i] > dp[j][k] + dp[j][i ^ k])
62 dp[j][i] = dp[j][k] + dp[j][i ^ k];
63 }
64 }
65 sz = 0 ;
66 CLR(vis);
67 REP(j,N + M + 1 ) if (dp[j][i] !=- 1 ){
68 hp[sz ++ ]. set (j,dp[j][i]);
69 push_heap(hp, hp + sz, cmp);
70 }
71 while (sz){
72 int now = hp[ 0 ].v;
73 pop_heap(hp, hp + sz -- ,cmp);
74 if (vis[now]) continue ;
75 vis[now] = true ;
76 for ( int e = gg[now]; ~ e; e = edg[e].e){
77 int to = edg[e].v, td = dp[now][i] + edg[e].d;
78 if (dp[to][i] ==- 1 || dp[to][i] > td){
79 dp[to][i] = td;
80 hp[sz ++ ]. set (to,td);
81 push_heap(hp, hp + sz, cmp);
82 }
83 }
84 }
85 }
86 return dp[ 0 ][up - 1 ];
87 }
88
89 int main()
90 {
91 while ( ~ scanf( " %d %d %d " , & N, & M, & P)){
92 int u, v, d;
93 SET(gg, - 1 ); ecnt = 0 ;
94 REP(i,N + M){
95 scanf( " %d " , & d);
96 addedge( 0 ,i + 1 , d);
97 }
98 REP(i,P){
99 scanf( " %d %d %d " , & u, & v, & d);
100 addedge(u,v,d);
101 }
102 int ret = steiner();
103 printf( " %d\n " , ret);
104 }
105 return 0 ;
106 }