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 ; }