题目描述:给你k个n*m个矩阵 里面有不同的字母,每个图形可以用前面已有的矩阵变化过来(起初没有),花费是相同点不同字母的个数*w,或者全部赋值花费n*m*w;
问生成全部矩阵最少花费多少。
分析:把它构造成一个完全图,点是矩阵,边即两个举证之间的花费,所以问题转化为求最小生成树,注意dfs遍历树的时候只需要不走到父节点就行了,并不用标记所有点。
ac代码:
#include<bits/stdc++.h> using namespace std; struct Edge { int u,v,w; }edge[1100*1100]; bool cmp(Edge a,Edge b){ return a.w<b.w; } int n,m,k,w; int fa[1100],diff[1100][1100]; char ch[1100][20][20]; vector <int >vc[1100]; int get_diff(char a[][20],char b[][20]){ int ret=0; for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(a[i][j]!=b[i][j]) ret++; return ret; } int getfa(int x){ if(fa[x]!=x)return fa[x]=getfa(fa[x]); else return fa[x]; } int Kruscal(int eg){ sort(edge,edge+eg,cmp); for(int i=0;i<=k+1;i++){ fa[i]=i; vc[i].clear(); } int cnt=k+1,ans=0; for(int i=0;i<eg;i++){ int f1=getfa(edge[i].u); int f2=getfa(edge[i].v); if(f1!=f2){ fa[f1]=f2; ans+=edge[i].w; vc[edge[i].u].push_back(edge[i].v); vc[edge[i].v].push_back(edge[i].u); cnt--; if(cnt==1) break; } } return ans; } void dfs(int u,int fa){ for(int i=0,sz=vc[u].size();i<sz;i++){ int v=vc[u][i]; if(v!=fa){ cout<<v<<' '<<u<<endl; dfs(v,u); } } } int main(){ ios::sync_with_stdio(0); cin.tie(0); // freopen("1.txt","r",stdin); cin>>n>>m>>k>>w; for(int i=1;i<=k;i++) for(int j=0;j<n;j++) cin>>ch[i][j]; for(int i=1;i<=k;i++) for(int j=i+1;j<=k;j++) diff[j][i]=diff[i][j]=get_diff(ch[i],ch[j])*w; int eg=0; for(int i=1;i<=k;i++){ edge[eg++]=(Edge){0,i,n*m}; for(int j=i+1;j<=k;j++) edge[eg++]=(Edge){i,j,diff[i][j]}; } cout<<Kruscal(eg)<<endl; dfs(0,0); }