pku 1639 Picnic Planning 最小度限制生成树
http://poj.org/problem?id=1639
题意:
见黑书。
思路:
最小限制树模板题:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b) #define ll long long #define inf 0x7f7f7f7f #define MOD 1073741824 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 100007 #define M 150 #define N 35 using namespace std; //freopen("din.txt","r",stdin); struct node { int u,w; node(int _u,int _w) { u = _u; w = _w; } friend bool operator < (node a,node b) { return a.w > b.w; } }; int dis[N],pre[N]; int col[N],near[N]; int Msd[N]; int mat[N][N]; priority_queue<node>q; map<string,int>mp; int res,n; int prim(int s,int id) { int res = 0,i; while (!q.empty()) q.pop(); q.push(node(s,0)); dis[s] = 0; while (!q.empty()) { node cur = q.top(); q.pop(); int u = cur.u; int w = cur.w; if (!col[u]) { col[u] = id; res += w; for (i = 1; i <= n; ++i) { if (!col[i] && mat[u][i] && dis[i] > mat[u][i]) { dis[i] = mat[u][i]; pre[i] = u; q.push(node(i,dis[i])); } } } } return res; } void dfs(int u,int fa,int maxside) { Msd[u] = maxside > mat[fa][u] ? maxside : mat[fa][u]; for (int i = 1; i <= n; ++i) { if (mat[u][i] && i != fa && (pre[u] == i || pre[i] == u)) dfs(i,u,Msd[u]); } } void solve(int k) { int i; for (i = 0; i <= n; ++i) { dis[i] = inf; col[i] = 0; pre[i] = 0; near[i] = 0; } col[0] = 1;//标记每一个最小生成树,先将根节点计入1 res = 0; int num = 0; for (i = 1; i <= n; ++i) { if (!col[i]) res += prim(i,++num);//分别计算最小生成树 } //计算每个最小生成树里距离s的最短距离 for (i = 1; i <= n; ++i) { int mk = col[i]; if (mat[0][i] && (near[mk] == 0 || mat[0][i] < mat[0][near[mk]])) near[mk] = i; } //连接每个最小生成树到根节点s的最短距离同时更新每个节点可能连接的最大边权值 CL(Msd,0); for (i = 1; i <= num; ++i) { res += mat[0][near[i]]; mat[0][near[i]] = mat[near[i]][0] = 0;//将该点消除 dfs(near[i],0,0);//求出改最小生成树以0为根节点的树根到每个节点之间的最大边权值 } k = k - num;//此时形成num度最小生成树 while (k--) { int tmp = 0;//找出Msd[tmp] - mat[0][tmp]的最大值 for (i = 1; i <= n; ++i) { if (mat[0][i] && (tmp == 0 || Msd[tmp] - mat[0][tmp] < Msd[i] - mat[0][i])) tmp = i; } if (Msd[tmp] <= mat[0][tmp]) break;//如果不能使度限制生成树继续减小跳出 res -= (Msd[tmp] - mat[0][tmp]); mat[0][tmp] = mat[tmp][0] = 0;//将改变置为0,表示不能再枚举了,已经加入最小限度生成树 // int p = 0; for (i = tmp; pre[i] != 0; i = pre[i]) { if (p == 0 || mat[p][pre[p]] < mat[i][pre[i]]) p = i; } pre[p] = 0; dfs(tmp,0,0); } printf("Total miles driven: %d\n",res); } int main() { int i,m; string s1,s2; int w; while (~scanf("%d",&m)) { mp.clear(); CL(mat,0); mp["Park"] = 0; n = 0; //printf("%d\n",mp.count("Park")); for (i = 0; i < m; ++i) { cin>>s1>>s2>>w; if (!mp.count(s1)) mp[s1] = ++n; if (!mp.count(s2)) mp[s2] = ++n; int tx = mp[s1]; int ty = mp[s2]; //建图 if (!mat[tx][ty] || mat[tx][ty] > w) mat[tx][ty] = mat[ty][tx] = w; } int k; cin>>k; solve(k); } return 0; }