UVA 1151

MST ;

不过有 Q种 特殊方案,可以只花费C【i】 (0 < i < Q )

对于方案的选取,可以状态压缩

先直接生成MST ,并把边存起来;

枚举 状态

对于方案, 链接点, 如有剩下的点没有处理; 则剩下的边必会在原MST中的边选;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1000 + 31;
struct Edges
{
    int x, y;
    int val;
    bool operator < (const Edges a) const { return val < a.val; }
}E[maxn * maxn];
 Edges Line[maxn];
 int X[maxn],Y[maxn];
 int Cost[maxn], st[10][maxn];
 int Cnt,N,Q,Ans;
 int Pre[maxn];

 int Find(int x)
 {
     int r = x;
     while(r != Pre[r]) r = Pre[r];
     return Pre[x] = r;
 }

 bool Union(int x,int y)
 {
     int ax = Find(x); int ay = Find(y);
     if(ax == ay) return false;
     Pre[ax] = ay;
     return true;
 }

 void Init()
 {
     for(int i = 0; i < maxn; ++i) Pre[i] = i;
 }

 void Solve(int Status);

 int main()
 {
     ios::sync_with_stdio(false);
     cin.tie(0);
     int t;
     cin >> t;
     bool Jug = false;
     while(t--)
     {
         if(Jug != false) cout <<endl;
         Jug = true; /// 在这里无限WA, 看题毛病多..........
         cin >> N >> Q;
         for(int i = 0; i < Q; ++i)
         {
             cin >> st[i][0] >> Cost[i];
             for(int j = 1; j <= st[i][0]; ++j)
                cin >> st[i][j];
         }
         for(int i = 1; i <= N; ++i)
            cin >> X[i] >> Y[i];
         Cnt = 0;
         for(int i = 1; i < N; ++i)
            for(int j = i+1; j <= N; ++j)
         {
            E[Cnt].x = i, E[Cnt].y = j;
            E[Cnt++].val = (X[i]-X[j])*(X[i]-X[j]) + (Y[i]-Y[j])*(Y[i]-Y[j]);
         }
         sort(E,E+Cnt);
         Init();
         int ee = 0;
         Ans = 0;
         for(int i = 0; i < Cnt; ++i)
         {
             if(Union(E[i].x, E[i].y))
             {
                 Line[ee] = E[i];
                 Ans += E[i].val;
                 ee++;
             }
             if(ee == N-1) break;
         }
         for(int i = 1; i < (1<<Q); ++i)
            Solve(i);
         cout << Ans <<endl;
     }
     return 0;
 }

 void Solve(int Status)
 {
     Init();
     int ret = 0, e = 0;
     for(int i = 0; i < Q; ++i)
     {
         if((1<<i) & Status)
         {
             for(int j = 1; j < st[i][0]; ++j)
             {
                 if(Union(st[i][j], st[i][j+1]))
                 {
                     e++;
                 }
             }
             //cout << i << "   " << ret << "   " << Cost[i] <<endl;
             ret += Cost[i];
         }
     }
     if(e == N-1)
     {
         //cout << ret << "   " << Status <<endl;
         Ans = min(Ans, ret);
         return ;
     }
     for(int i = 0; i < N; ++i)
     {
         if(Union(Line[i].x, Line[i].y))
            e++, ret += Line[i].val;
         if(e == N-1) break;
     }
     //c/out << ret << "   " << Status <<endl;
     Ans = min(Ans, ret);
     return ;
 }

转载于:https://www.cnblogs.com/aoxuets/p/4753519.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值