第十一章例题 uva 1151 C- Buy or Build

自己用dfs实现枚举 + 对刘汝佳大神用二进制枚举的解读 

/*SE:wn------王宁*/
/*Buy or Build 输入输出解读
输入:
城市编号从1-n 
1.告诉你有几个case

2.1 n of cities in the country (1 ≤ n ≤ 1000)  2.2 followed by the number q of existing subnetworks (0 ≤ q ≤ 8).

3.(接下来q行) 
这个网络中的城市数量 + 这个网络买下来的花费 (not greater than 2 × 1e6)+ 网络中城市们的编号

4.(接下来n行)
城市的x y坐标  (ranging from 0 to 3000) c

输出:要有空行 
*/
/*1.运行过程出现的bug原因
当我以为建立网络的花费是距离而不是距离平方的时候
我用%d输出,结果虽然result已经是正确答案(样例中是12.多)
但是这样就输出了负数——检查了一遍才发现
2.重复运行的原因 ! 重复运行是必须的,对于我这种写法来说,
如果一个套餐都没有, v0是不是永远不可能==-1? 
之前的想法(dfs边界判断条件应该是
 if(v0==qn-1),因为是从0开始计数的,而choose在开头
 就已经独立于if-else语句初始化好了)对重复的解读是对的,
 但是没有考虑到特殊情况,结果为了优化又搞出了bug 
 所以还是 if(v0==qn)*/
#include
using namespace std; 
struct edge{
  int u,v,d;
  bool operator < (const edge& dhs) const{
    return d < dhs.d;
  }
};
struct point{
  int x,y;
};
const int maxn=1000+5;

vector database;//经过无套餐参与的最小生成树边集 
vector total;//经过套餐可能的参与的需要探索的总边集 
vector tc[10];//每个套餐含有的边集 
vector v;//经过第一次欧几里得距离的计算处理后得到的原始边集 

vector p;//存储城市的位置的点集 
vector a;//接收套餐中城市编号的数组 
struct edge t;//接受边的临时变量 
struct point pt;//接受城市位置的临时变量 
int first=1;
int fa[maxn];
int nc,qn;//几个城市,几个套餐
int choose[10];//套餐有没有被选择的状态数组
int result=2000000000,ans;//ans是每次枚举套餐得到的局部最小值,result保存全局最小值
int cost[10];//每个套餐花的钱
int find(int x){
  return x==fa[x]?x:fa[x]=find(fa[x]);
}
/*枚举使用了dfs——因为不知道有几个套餐
——知道了用for来写也很丑
——对,我懒得写
——好了,你?怎么还在看
——我不会写行了嘛555……*/
void dfs(int v0, int state){//state表示该套餐有没有被选择,0=没有,1=选择了
  choose[v0]=state;
  if(v0==qn){
    total=database;
    ans=0;
    /*来得到需要处理的边集,注意
    1.vector变量之间可以直接赋值
    2.它的insert用法*/
    for(int i=0;i>runs;
  for(run=1;run<=runs;run++){
    cin>>nc>>qn;
    /*处理套餐*/
    for(i=0;i>m>>c; cost[i]=c; a.clear(); tc[i].clear(); 
      for(j=0;j

———————帅气不失风度的分割线————————


// UVa1151 Buy or Build
// Rujia Liu processed by SE:wn------王宁
#include
#include
#include
#include
#include
using namespace std;

const int maxn = 1000 + 10;
const int maxq = 8;
int n;
int x[maxn], y[maxn], cost[maxq];
vector subn[maxq];

int pa[maxn];
int findset(int x) { return pa[x] != x ? pa[x] = findset(pa[x]) : x; } 

struct Edge {
  int u, v, d;
  Edge(int u, int v, int d):u(u),v(v),d(d) {}
  bool operator < (const Edge& rhs) const {
    return d < rhs.d;
  }
};

// initialize pa and sort e before calling this method
// cnt is the current number of components
int MST(int cnt, const vector& e, vector& used) {
  if(cnt == 1) return 0;
  int m = e.size();
  int ans = 0;
  used.clear();
  for(int i = 0; i < m; i++) {
    int u = findset(e[i].u), v = findset(e[i].v);
    int d = e[i].d;
    if(u != v) {
      pa[u] = v;
      ans += d;
      used.push_back(e[i]);
      if(--cnt == 1) break;
    }
  }
  return ans;
}

int main() {
  int T, q;
  scanf("%d", &T);
  while(T--) {
    scanf("%d%d", &n, &q);
    for(int i = 0; i < q; i++) {
      int cnt;
      scanf("%d%d", &cnt, &cost[i]);
      subn[i].clear();
      while(cnt--) {
        int u;
        scanf("%d", &u);
        subn[i].push_back(u-1);
      }
    }
    for(int i = 0; i < n; i++) scanf("%d%d", &x[i], &y[i]);

    vector e, need;
    for(int i = 0; i < n; i++)
      for(int j = i+1; j < n; j++) {
        int c = (x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]);
        e.push_back(Edge(i, j, c));
      }

    for(int i = 0; i < n; i++) pa[i] = i;
    sort(e.begin(), e.end());

/*对刘汝佳大神用二进制位运算来实现使用for循环的枚举*/
	int ans = MST(n, e, need);//没有购买套餐的状态
    for(int mask = 0; mask < (1< dummy;
      ans = min(ans, c + MST(cnt, need, dummy));
    }
    printf("%d\n", ans);
    if(T) printf("\n");
  }
  return 0;
}

 

 

你可能感兴趣的:(八月暑期集训)