题意:给你n个串,每个串长度不超过10。小明想联想记单词,如果对两个词进行联想记忆 花费 w*k (w为给定值,k为字符串之间对应位置不同的个数)。当然也可以不联想记忆,这样就只花费字符串长度的体力
问记忆完所有单词花费最小体力。
思路:把每个串当作一个结点,不同联想记忆的花费为路径权值(要将w*k与 串本身长度进行比较选最小作为权值),然后跑一遍prim算法即可
完整代码:
#include <iostream> #include <cstdio> #include <vector> #include <cstring> #include <string> #include <queue> using namespace std; typedef pair<int,int> pii; const int maxm = 1e6+10; const int inf = 0x3f3f3f3f; const int maxn = 1e3+5; int top; int n,m,cost; int ans; string s[maxn]; int head[maxn]; int vis[maxn]; int dist[maxn]; //堆重载 struct cmp{ bool operator() (pii a, pii b){ return a.first>b.first; } }; struct Edge{ int u,v,w; int next; }edge[maxm]; void init(){ memset(head,-1,sizeof(head)); memset(edge,0,sizeof(edge)); memset(dist,-1,sizeof(dist)); memset(vis,0,sizeof(vis)); top = 0; ans = 0; } void add(int v,int u,int w){ edge[top].u = u; edge[top].v = v; edge[top].w = w; edge[top].next = head[u]; head[u] = top++; } void prim(int s){ int i; priority_queue<pii,vector<pii> ,cmp>Q; dist[s] = 0; vis[s] = 1; for(i = head[s]; ~i; i = edge[i].next){ //先把到起点边的距离初始化为其本身 dist[edge[i].v] = edge[i].w; Q.push(make_pair(dist[edge[i].v],edge[i].v)); } while(!Q.empty()){ pii t = Q.top(); Q.pop(); if(vis[t.second]) continue; ans += t.first; vis[t.second] = 1; for(i = head[t.second]; ~i ;i = edge[i].next){ int j = edge[i].v; //没被访问没有连接或者权值太小 if(!vis[j]&&(dist[j]>edge[i].w||dist[j]==-1)){ dist[j] = edge[i].w; Q.push(make_pair(dist[j],j)); } } } } int getCost(int i,int j){ int res = 0; for(int k=0;k<m;k++){ if(s[i][k]!=s[j][k]) res++; } return res; } int main(){ while(cin>>n>>m>>cost){ init(); for(int i =0 ;i<n;i++) cin>>s[i]; for(int i = 0;i<n;i++){ for(int j = 0;j<n;j++){ if(i==j) continue; int c = min(cost*getCost(i,j),m); add(i,j,c); } } prim(0); cout<<ans+m<<endl; } }