Codeforces Round # 597 (. Div 2) D. Shichikuji and Power Grid [+ minimum spanning tree thinking: constructing a virtual point]

Topic link: http: //codeforces.com/problemset/problem/1245/D

Thinking

Into the right side of the right point, to build a "super-root", which is set for the number 0, which is connected to the original n points, n edges are formed, this assignment right side edges n is n points the right point.
The rest is all right edge is sequentially stored in the array.

Then that is all the edge weights in ascending order, minimum spanning tree to run again.

(Do I thought about the possibility and the minimum spanning tree, but did not expect to build a new root point and then right into the right side of this magical operation, which is really quite a clever idea!)

AC Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e3+10;
ll n,cnt,num,tot,sum,ans,pre[N],power[N];
struct edge
{
    ll a,b,w;
}e[N*N],line[N*N];
struct node
{
    ll x,y,w,val;
}p[N];
ll find(ll x)
{
    if(x!=pre[x])pre[x]=find(pre[x]);
    return pre[x];
}
void join(ll a,ll b)
{pre[find(a)]=find(b);}
bool cmp(edge s1,edge s2)
{return s1.w<s2.w;}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>p[i].x>>p[i].y;
    for(int i=1;i<=n;i++)
    {
        cin>>p[i].val;//点权
        e[++cnt].a=0;//起点为新根0
        e[cnt].b=i;//终点为i
        e[cnt].w=p[i].val;//点权转化为边权
    }
    for(int i=1;i<=n;i++)
        cin>>p[i].w;//暂时边权
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        {
            e[++cnt].a=i;
            e[cnt].b=j;
            e[cnt].w=(abs(p[i].x-p[j].x)+abs(p[i].y-p[j].y))*(p[i].w+p[j].w);//计算边权,存入e数组
        }
    for(int i=0;i<=n;i++)//从0开始初始化
        pre[i]=i;
    sort(e+1,e+cnt+1,cmp);
    for(int i=1;i<=cnt;i++)
    {
        if(find(e[i].a)!=find(e[i].b))
        {
            join(e[i].a,e[i].b);
            sum++;
            ans+=e[i].w;
            if(e[i].a==0)power[++num]=e[i].b;//发电站
            else line[++tot]=e[i];//要连线的边
            if(sum==n)break;//总共n+1个点(因为加了一个根),如果已经连了n条边,就结束
        }
    }
    printf("%lld\n",ans);//最小权值和
    printf("%lld\n",num);
    for(int i=1;i<=num;i++)
        i==num?printf("%lld\n",power[i]):printf("%lld ",power[i]);
    printf("%lld\n",tot);
    for(int i=1;i<=tot;i++)
        printf("%lld %lld\n",line[i].a,line[i].b);
    return 0;
}
Published 72 original articles · won praise 91 · views 30000 +

Guess you like

Origin blog.csdn.net/ljw_study_in_CSDN/article/details/103432720