poj3123
题意:
给定n个城市和m条可选择修建的道路
下面n行给出每个城市的名字
下面m行给出每条道路及修建该道路的花费。
下面4行,每行给出一对城市。
目标:使得每对城市连通(不同对之间可以不连通)所需要修建的最小花费。
数据保证存在可行解
思路:
首先如果这个问题问的是所有城市都连通,就是一个最小生成树的问题。这里就相当于多个最小生成树的 问题。
图里我们只关心最后的4行8个点,所以我们状压这8个点。这里把(1,5)(2,6)(3,7)(4,8)配对,即重新复制了hash1的值,便于处理
设dp[mask][i] 表示以i为根 ,mask为在 i 的子树里的点集的最小花费。(注意i这个点是不一定出现在j里的,因为i点可以是除这8个点之外的点)
过程中用spfa求最短路
转移:
1、从2个点集合并得到
dp[mask][i] = min( dp[ mask1 ][i]+dp[ mask2 ][i])
其中mask1 & mask2 = 1<<i,mask1 | mask2 = mask
即我们把 根为i ,点集为mask1 的子树和根同样为i 点集为mask2的子树的花费和 就是根为i ,点集为 mask = mask1+mask2 的一个花费,取个最小即可。
2、把i点加到一个子树上得到。
我们枚举这个子树,显然这个子树的点集就是mask,当然根是不确定的,因为根不一定是j中的点,所以枚举根K。
这样我们就能得到子树的状态是 dp[mask][K] , 而加入i点时 可以和树上任意一个点相连
#include<iostream> #include<string> #include<algorithm> #include<cstdio> #include<queue> #include<cstring> #include<map> using namespace std; const int maxn=30; map<string,int>hsh; queue<int>q; bool vis[maxn]; int hash1[maxn],dp[1<<8][maxn],dis[maxn][maxn],num[maxn],ans[1<<4]; int main(){ int n,m; while(scanf("%d%d",&n,&m),n || m){ memset(dp,-1,sizeof dp); memset(dis,-1,sizeof dis); memset(ans,-1,sizeof ans); memset(hash1,-1,sizeof hash1); hsh.clear(); for(int i=0;i<n;i++){string s;cin>>s;hsh[s]=i;dis[i][i]=0;dp[0][i]=0;} while(m--){string a,b;int c;cin>>a>>b>>c;int x=hsh[a],y=hsh[b];dis[x][y]=dis[y][x]=dis[x][y]==-1?c:min(dis[x][y],c);} for(int i=0;i<8;i++){ string s;cin>>s; hash1[hsh[s]]=((i&1)<<2)|(i>>1); dp[1<<hash1[hsh[s]]][hsh[s]]=0; dp[0][hsh[s]]=-1; num[hash1[hsh[s]]]=hsh[s]; } for(int mask=0;mask< 1<<8;mask++){ for(int i=0;i<n;i++){ if(hash1[i]!=-1 && !(mask>>hash1[i]&1))continue; for(int mask1=(mask-1)&mask;mask1;mask1=(mask1-1)&mask){ int mask2=mask^mask1 |((hash1[i]!=-1)?1<<hash1[i]:0); if(dp[mask1][i]!=-1 && dp[mask2][i]!=-1)dp[mask][i]=dp[mask][i]==-1?dp[mask2][i]+dp[mask1][i]:min(dp[mask][i],dp[mask2][i]+dp[mask1][i]); } while(!q.empty())q.pop(); for(int i=0;i<n;i++)if(dp[mask][i]!=-1){q.push(i);vis[i]=true;}else vis[i]=false; while(!q.empty()){ int u=q.front();q.pop();vis[u]=false; for(int v=0;v<n;v++) if(dis[u][v]!=-1){ if(dp[mask][v]==-1 || dp[mask][v]>dp[mask][u]+dis[u][v]){ dp[mask][v]=dp[mask][u]+dis[u][v]; if(!vis[v]){q.push(v);vis[v]=true;} } } } } for(int mask=0;mask< 1<<4;mask++){ for(int i=0;i<4;i++) if(mask>>i & 1){ans[mask]=dp[mask<<4 | mask][num[i]];break;} for(int mask1=(mask-1)&mask;mask1;mask1=(mask1-1)&mask){ int mask2=mask^mask1; if(ans[mask1]!=-1 && ans[mask2]!=-1)ans[mask]=ans[mask]==-1?(ans[mask1]+ans[mask2]):min(ans[mask],ans[mask1]+ans[mask2]); } } } printf("%d\n",ans[(1<<4)-1]); } return 0; }

浙公网安备 33010602011771号