POJ 2784 Buy or Build最小生成ツリー
2086 ワード
シナリオを列挙して最小生成ツリーを作成します.
------------
------------
------------
const int maxn=1100;
const int maxm=10000;
int n,q;
vector<int>g[10];
int c[10];
struct Point{
int x,y;
int getValueTo(Point p){
return (p.x-x)*(p.x-x)+(p.y-y)*(p.y-y);
}
}p[maxn];
struct EDGE{
int u,v,d;
bool operator<(const EDGE& rhs) const{
return d<rhs.d;
}
}e[maxn*maxn];
int edge;
int pa[maxn];
void makeset(int n){
for (int i=0;i<=n;i++) pa[i]=i;
}
int findset(int x){
if (x!=pa[x]) pa[x]=findset(pa[x]);
return pa[x];
}
bool unionset(int x,int y){
x=findset(x);
y=findset(y);
if (x!=y) {
pa[x]=y;
return true;
}
return false;
}
int kruskal(){
int ans=0;
for (int i=0;i<edge;i++){
if (unionset(e[i].u,e[i].v)){
ans+=e[i].d;
}
}
return ans;
}
int main(){
while (~scanf("%d%d",&n,&q)){
for (int i=0;i<q;i++){
int cnt;
scanf("%d%d",&cnt,&c[i]);
for (int j=0;j<cnt;j++){
int tmp;
scanf("%d",&tmp);
g[i].push_back(tmp);
}
}
for (int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y);
edge=0;
for (int i=1;i<=n;i++){
for (int j=i+1;j<=n;j++){
e[edge].u=i;
e[edge].v=j;
e[edge++].d=p[i].getValueTo(p[j]);
}
}
sort(e,e+edge);
makeset(n);
int ans=kruskal();
for (int s=1;s<(1<<q);s++){
makeset(n);
int cost=0;
for (int i=0;i<q;i++){
if (s&(1<<i)){
cost+=c[i];
for (int j=1;j<sz(g[i]);j++){
unionset(g[i][j-1],g[i][j]);
}
}
}
ans=min(ans,cost+kruskal());
}
printf("%d
",ans);
}
return 0;
}
------------