最小生成树算法简单
只是增加了一些新的东西,对于需要最小生成树算法 和中 并检查使用的一系列 还有一些更深入的了解。
方法的一些复杂问题
#include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int maxn = 1005; struct point { int x; int y; }pp[maxn]; struct edge { int s; int e; int dist; }l[maxn*maxn]; int n,q,m; int p[maxn]; vector<int> g[10]; int c[10]; int distance_(point a,point b) { return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y); } int cmp(edge a,edge b) { return a.dist < b.dist; } int find_(int x) { return p[x]==x?x:p[x]=find_(p[x]); } bool merge_(int a,int b) { int x=find_(a); int y=find_(b); if(x==y) return false; p[x]=y; return true; } int kruskal() { int ans=0; int num=0; for(int i=0;i<m&&num<n-1;i++) { if(merge_(l[i].s,l[i].e)) { num++; ans+=l[i].dist; } } return ans; } void solve() { for(int i=0;i<=n;i++) p[i]=i; int ans = kruskal(); for(int s=1;s<(1<<q);s++) { int cost=0; for(int tt=0;tt<=n;tt++) p[tt]=tt; for(int j=0;j<q;j++) { if(!((s>>j)&1)) continue; cost+=c[j]; for(int k=0;k<g[j].size();k++) { merge_(g[j][k],g[j][0]); } } ans=min(ans,cost+kruskal()); } printf("%d ",ans); } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&q); for(int i=0;i<10;i++) g[i].clear(); for(int i=0;i<q;i++) { int cnt; scanf("%d%d",&cnt,&c[i]); int a; for(int j=0;j<cnt;j++) { scanf("%d",&a); g[i].push_back(a); } } for(int i=1;i<=n;i++) { scanf("%d%d",&pp[i].x,&pp[i].y); } m=0; for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { l[m].s=i; l[m].e=j; l[m++].dist=distance_(pp[i],pp[j]); } } sort(l,l+m,cmp); solve(); if(t) printf(" "); } return 0; }
鉴于需要使用几个选项 枚举子 算法。
在上面的解决方法。它使用的二进制计数的方法的帮助的一个子集。枚举算法的子集只适用于相对小的一组元素的。
采取结构上述表示的方法edge该方法,与其说开放数组。我觉得跟结构可以更可读的代码。