题目信息:http://blog.csdn.net/acm_cxq/article/details/52192026
题意:
n个城市1--n,有m座桥可以城市,编号为1的城市是皇宫。修建每座桥的费用为c,每个城市的人口为pi。总费用为k。
求从皇宫出发,修建桥连接尽可能多的城市,城市相互直接或者间接连接通向皇宫,使得跟皇宫相连的所有城市的人口数之和为最大值,且费用不超过k。(无向图)
思路:巧妙运用二进制保存所有城市的状态,n个城市,每个城市选或不选,有2^n种可能。
1代表选,0代表不选。(1号城市必须入选)
如n等于4时,4个城市。
那么 1<<4等于16种可能,
如1101,代表第1,3,4城市入选,第二个城市不选。
然后将选入的城市的编号保存在一个数组里面,用prim算法求得入选城市相连后的花费。
在所有状态中,找出总人口最多的那个状态。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 20;
const int INF = 999999999;
int n;//城市,编号1--n,1为皇帝宫
int m;//可以修的路
int cost;//最大花费
int weight[maxn];//每个城市对应的人口数
int graph[maxn][maxn];//修建两个城市间路的费用
int city[maxn];//被选的城市
int state;//状态
int COST,temp;//被选的城市的总人数
int pos;//被选的城市个数
void init() {
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
graph[i][j] = INF;
if(i==j) graph[i][j] = 0;
}
}
}
int prim(int n,int pos) {
int mincost[maxn];
bool used[maxn];
for(int i=0; i<n; i++) {
mincost[city[i]] = graph[city[i]][pos];
used[city[i]] = false;
}
mincost[pos] = 0;
int res = 0;
while(true) {
int v = -1;
//从未被true的顶点中选取从已经选的点到其权值最小的顶点
for(int u=0; u<n; u++) {
if(!used[city[u]]&&(v==-1||mincost[city[u]]<mincost[city[v]])) v = u;
}
if(v==-1) break;//更新完了
used[city[v]] = true;
res+=mincost[city[v]];
if(res>cost) return -1;
for(int u = 0; u<n; u++) {
mincost[city[u]] = min(mincost[city[u]],graph[city[v]][city[u]]);
}
}
return res;
}
int main() {
int cases;
cin>>cases;
int a,b,c;
while(cases--) {
cin>>n>>m>>cost;
memset(city,0,sizeof(city));
for(int i=1; i<=n; i++) {
cin>>weight[i];
}
for(int i=0; i<m; i++) {
cin>>a>>b>>c;
graph[a][b] = graph[b][a] = min(graph[a][b],c);
}
state = 1<<n;//枚举2的n次方中可能性
COST = -1;
for(int i = state-1; i>0; i--) {
//第一个城市必须入选,不然就进入下一个状态
if(!(i&1)) continue;//如果这些状态中第一个城市没有入选,那么直接跳过
pos = 0;
temp = 0;
for(int j=0; j<n; j++) {
//判断哪些城市入选
if((i>>j)&1) {
city[pos++] = j+1;//表示第j+1个城市入选
temp += weight[j+1];//加上第j+1个城市的人口数
}
}
int cost = prim(pos,city[0]);//以第一个城市到各个被选城市的最小花费
//如果总花费不大于给定的总价,选择总人数最多的方案
if(cost!=-1) {
COST = max(COST,temp);
if(i==state-1) break;//如果所有城市都入选,那人口总数必定是最大的!!!
}
}
cout<<COST<<endl;
}
}