POJ 1789 (最小生成树 Prim)
题目描述:给予n个长度为7的字符串,定义两字符串间的代价为同一位置不同的字符的个数,现在要联通所有的字符串求最小代价。
思路:一开始使用Krustal算法,然而因为是稠密图导致TLE,换用Prim。
Krustal:(TLE)
#include <cstdio> #include <algorithm> #include <iostream> #include <queue> #define N 2005 using namespace std; struct e{ int fi,sec,val; e(){} e(int a,int b,int c):fi(a),sec(b),val(c){} bool operator<(const e&X)const{ return val>X.val; } }; class graph{ int n; char str[N][8]; int belong[N]; priority_queue<e>edge; int check(char *a,char *b){ int cnt = 0; char *e = a+7; while (a!=e){ if(*a!=*b)cnt++; a++,b++; } return cnt; } int find(int x){ return x==belong[x]?x:belong[x] = find(belong[x]); } bool UNION(int a,int b){ int x = find(a); int y = find(b); if(x!=y){ belong[y] = x; return true; } else return false; } public: int init(){ cin>>n; for(int i = 1 ; i <= n ; ++i){ scanf("%s",str[i]); belong[i] = i; } return n; } void build(){ for(int i = 1 ; i < n ; ++i){ for(int j = i+1 ; j <= n ; ++j){ edge.push(e(i,j,check(str[i],str[j]))); } } } int get_ans(){ int x,y; e tmp; int ans = 0; while (!edge.empty()){ tmp = edge.top(); edge.pop(); if(UNION(tmp.fi,tmp.sec)){ ans+=tmp.val; } } return ans; } }; graph ss; int main(){ while (ss.init()){ ss.build(); cout<<"The highest possible quality is 1/"; cout<<ss.get_ans()<<".\n"; } }
Prim(AC):
#include <cstdio> #include <algorithm> #include <iostream> #include <queue> #include <cstring> #define N 2005 using namespace std; class graph{ int n; char str[N][8]; int plant[N][N],dis[N]; bool inset[N]; int check(char *a,char *b){ int cnt = 0; char *e = a+7; while (a!=e){ if(*a!=*b)cnt++; a++,b++; } return cnt; } public: int init(){ cin>>n; for(int i = 1 ; i <= n ; ++i){ scanf("%s",str[i]); } return n; } void build(){ for(int i = 1 ; i < n ; ++i){ for(int j = i+1 ; j <= n ; ++j){ plant[i][j] = plant[j][i] = check(str[i],str[j]); } } } int get_ans(){ int ans = 0; memset(inset,0, sizeof(inset)); memset(dis,0x3f3f3f3f, sizeof(dis)); dis[1] = 0; for(int i = 1 ; i <= n ; ++i){ int mark = 0; for(int j = 1 ; j <= n ; ++j){ if(!inset[j]) if(!mark)mark = j; else if(dis[j]<dis[mark])mark = j; } if(!mark)break; inset[mark] = true; ans+=dis[mark]; for(int j = 1 ; j <= n ; ++j){ if(!inset[j]){ dis[j] = min(dis[j],plant[mark][j]); } } } return ans; } }; graph ss; int main(){ while (ss.init()){ ss.build(); cout<<"The highest possible quality is 1/"; cout<<ss.get_ans()<<".\n"; } } //在稠密图中比较实用,每次找出距离最小的点加入集合,然后更新剩下不在集合中的点的最小距离(只用以新加入的点做参考) //答案正确 内存使用:16192KB 运行时间:422ms