您的位置:首页 > 产品设计 > UI/UE

POJ 2784 Buy or Build(二进制枚举 + 最小生成树)

2016-09-03 21:55 459 查看
Buy or Build

Description

World Wide Networks (WWN) is a leading company that operates large telecommunication networks. WWN would like to setup a new network in Borduria, a nice country that recently managed to get rid of its military dictator Kurvi-Tasch and which is now seeking for
investments of international companies (for a complete description of Borduria, have a look to the following Tintin albums ``King Ottokar's Sceptre", ``The Calculus Affair" and ``Tintin and the Picaros"). You are requested to help WWN todecide how to setup
its network for a minimal total cost. 
Problem 

There are several local companies running small networks (called subnetworks in the following) that partially cover the n largest cities of Borduria. WWN would like to setup a network that connects all n cities. To achieve this, it can either build edges between
cities from scratch or it can buy one or several subnetworks from local companies. You are requested to help WWN to decide how to setup its network for a minimal total cost. 
All n cities are located by their two-dimensional Cartesian coordinates. 

There are q existing subnetworks. If q>=1 then each subnetwork c ( 1<=c<=q ) is defined by a set of interconnected cities (the exact shape of a subnetwork is not relevant to our problem). 

A subnetwork c can be bought for a total cost wc and it cannot be split (i.e., the network cannot be fractioned). 

To connect two cities that are not connected through the subnetworks bought, WWN has to build an edge whose cost is exactly the square of the Euclidean distance between the cities.

You have to decide which existing networks you buy and which edges you setup so that the total cost is minimal. Note that the number of existing networks is always very small (typically smaller than 8). 
A 115 Cities Instance 

Consider a 115 cities instance of the problem with 4 subnetworks (the 4 first graphs in Figure 1). As mentioned earlier the exact shape of a subnetwork is not relevant still, to keep figures easy to read, we have assumed an arbitrary tree like structure for
each subnetworks. The bottom network in Figure 1 corresponds to the solution in which the first and the third networks have been bought. Thin edges correspond to edges build from scratch while thick edges are those from one of the initial networks. 

Input

The first line contains the number n of cities in the country ( 1<=n<=1000 ) followed by the number q of existing subnetworks ( 0<=q<=8 ). Cities are identified by a unique integer value ranging from 1 to n . The first line is followed by q lines (one per subnetwork),
all of them following the same pattern: The first integer is the number of cities in the subnetwork. The second integer is the the cost of the subnetwork (not greater than 2 x 106 ). The remaining integers on the line (as many as the number of cities
in the subnetwork) are the identifiers of the cities in the subnetwork. The last part of the file contains n lines that provide the coordinates of the cities (city 1 on the first line, city 2 on the second one, etc). Each line is made of 2 integer values (ranging
from 0 to 3000) corresponding to the integer coordinates of the city.
Output

Your program has to write the optimal total cost to interconnect all cities.
Sample Input
7 3
2 4 1 2
3 3 3 6 7
3 9 2 4 5
0 2
4 0
2 0
4 2
1 3
0 5
4 4

Sample Output
17

Hint

Sample Explanation: The above instance is shown in Figure 2. An optimal solution is described in Figure 3 (thick edges come from an existing network while thin edges have been setup from scratch). 





Figure 3: An optimal solution of the 7 City instance in which which the first and second existing networkshave been bought while two extra edges (1, 5) and (2, 4) 



题目大意:平面上有N个点,你的任务是让N个点连通。为此,你可以新建一些边,费用等于两个端点的欧几里德距离的平方。另外有q个套餐可以购买,如果你购买了第i个套餐,该套餐中的所有节点将变得相互连通。第i个套餐的花费为Ci,求使所有点连通的最小花费。

解题思路:先求一次原图的最小生成树,得到N - 1条边,然后每次枚举完套餐后只考虑套餐中的边和这N - 1条边。因为在Kruskal算法中,两端已经属于同一连通分量的边不会进入最小生成树。购买套餐以后,相当于一些边的权值变为0,而对于不再套餐中的每条边e,排序在e之前的边没有减少,反而多了一些权值为0的边,所以在原图Kruskal算法中没有被选取的边在后面的Kruskal算法中也不会被选取。另外,枚举套餐时,要利用二进制进行枚举。(PS:紫书上把欧几里德距离的平方印成了欧几里德距离,搞了半天才发现。。。)

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#define INF 1e9
const int maxn = 1005;
const int maxm = 1000005;
struct edge
{
int from,to,dis;
edge(int from,int to,int dis){
this -> from = from;
this -> to = to;
this -> dis = dis;
}
edge(){}
};
struct node
{
int cost;
std::vector<int> v;
};
edge edges[maxm];
node nodes[11];
int par[maxn],rank[maxn];
int n,q,e;
int x[maxn],y[maxn];
void init()
{
for(int i = 0;i <= n;i++){
par[i] = i;
rank[i] = 0;
}
}

void add_edge(int from,int to,int dis)
{
edges[e].from = from;
edges[e].to = to;
edges[e++].dis = dis;
}

int find(int x)
{
return par[x] == x ? x : par[x] = find(par[x]);
}

void unite(int x,int y)
{
x = find(x);
y = find(y);
if(x == y) return ;
if(rank[x] < rank[y]) par[x] = y;
else{
par[y] = x;
if(rank[x] == rank[y]) rank[x]++;
}
}

bool same(int x,int y)
{
return find(x) == find(y);
}

bool cmp(edge a,edge b)
{
return a.dis < b.dis;
}

int Kruskal()
{
int res = 0;
int cnt = 0;
for(int i = 0;i < e;i++){
edge ed = edges[i];
if(same(ed.from,ed.to)) continue;
unite(ed.from,ed.to);
res += ed.dis;
if(++cnt == n - 1) break;
}
return res;
}

int main(void)
{
int a,b,c,d;
while(scanf("%d %d",&n,&q) != EOF){
init();
for(int i = 0;i <= q;i++) nodes[i].v.clear();
e = 0;
for(int i = 0;i < q;i++){
scanf("%d %d",&a,&nodes[i].cost);
while(a--){
scanf("%d",&d);
nodes[i].v.push_back(d);
}
}
for(int i = 0;i < n;i++){
scanf("%d %d",&x[i],&y[i]);
}
for(int i = 0;i < n;i++){
for(int j = i + 1;j < n;j++){
int dis = pow(x[i] - x[j],2) + pow(y[i] - y[j],2);
add_edge(i + 1,j + 1,dis);
}
}
std::sort(edges,edges + e,cmp);
int sum,res;
res = Kruskal();
for(int i = 0;i < 1 << q;i++){
sum = 0;
init();
for(int j = 0;j < q;j++){
if(!(i & (1 << j))) continue;
sum += nodes[j].cost;
int len = (int)nodes[j].v.size();
for(int k = 1;k < len;k++){
unite(nodes[j].v[0],nodes[j].v[k]);
}
}
sum += Kruskal();
res = std::min(res,sum);
}
printf("%d\n",res);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  POJ