※P1194 买礼物
- 如果\(g[i][j] != 0\) ,则购买\(i\)后只需再花费\(g[i][j]\)购买\(j\)即可,于是从\(i\)向\(j\)连一条边权为\(g[i][j]\)的边
- 如果\(g[i][j] == 0\),则购买\(i\)后只能花费\(w\)购买\(j\),于是从\(i\)向\(j\)连一条边权为\(w\)的边
- 对所有的\(i,j∈[1,n]\)进行两边,保证原图一定是连通的(若每个物品都花费w购买,图为一条链)
- 对原图求\(MST\)即可
- 注意最后加上第一个点的花费\(w\)(第一个点只能通过\(w\)购买)
const int N=510;
int g[N][N];
int dist[N];
bool vis[N];
int n,w;
int prim()
{
memset(dist,0x3f,sizeof dist);
int res=0;
for(int i=0;i<n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
if(!vis[j] && (t==-1 || dist[t]>dist[j]))
t=j;
vis[t]=true;
if(i) res+=dist[t];
for(int j=1;j<=n;j++)
dist[j]=min(dist[j],g[t][j]);
}
return res+w;
}
int main()
{
cin>>w>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
cin>>g[i][j];
if(i!=j && !g[i][j]) g[i][j]=w;
else g[i][j]=min(g[i][j],w);
}
int t=prim();
cout<<t<<endl;
//system("pause");
}
也可转换成下列模型:
在原图基础上,建立虚拟结点\(0\)号点,向所有结点连一条边权为\(w\)的边,在图上求\(MST\)
const int N=510;
int g[N][N];
int dist[N];
bool vis[N];
int n,w;
int prim()
{
memset(dist,0x3f,sizeof dist);
int res=0;
for(int i=0;i<n+1;i++)
{
int t=-1;
for(int j=0;j<=n;j++)
if(!vis[j] && (t==-1 || dist[t]>dist[j]))
t=j;
vis[t]=true;
if(i) res+=dist[t];
for(int j=0;j<=n;j++)
dist[j]=min(dist[j],g[t][j]);
}
return res;
}
int main()
{
cin>>w>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
cin>>g[i][j];
if(i!=j && !g[i][j]) g[i][j]=INF;
}
for(int i=1;i<=n;i++) g[0][i]=g[i][0]=w;
int t=prim();
cout<<t<<endl;
//system("pause");
}
特殊数据
3 3
0 4 4
4 0 4
4 4 0