※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

原文地址:https://www.cnblogs.com/fxh0707/p/13622195.html