2017.8.17 NOIp膜你赛T1

第一题(diyiti.cpp/c/pas)
【Description】
农村已整改,套路深似海啊..
W村要想上网,一共有n个家庭,家所在位置可以用(x,y)的坐标表示出来
一个家庭上网可以通过下面两种方式上网:
1)直接连上网络,需要付出A的代价
2)蹭别人的网,和一家可以上网的家庭py,需要付出B*两地曼哈顿距离的代价
请问W村所有家庭都能上网的最小代价
【Input】
第一行三个整数n、A、B,意义如题
第二行到第n+1行,每行两个整数,代表xi、yi,意义如题
【Output】
一个整数,代表最小代价
【Sample Input】
5 10 2
0 0
0 1
1 0
1 1
100 100
【Sample Output】
26
【Data】
对于30%的数据 n<=3 A<=50 B<=5
对于60%的数据 n<=100 A<=1000 B<=20
对于100%的数据 n<=10^3 A<=10^4 B<=50 |xi|、|yi|<=2^15
【Tips】
定义两点曼哈顿距离为|Xi-Xj|+|Yi-Yj|

这题一开始以为是网络流,于是想了半天。。
于是没想出来。。
于是就想贪心随便弄弄
大概就是距离代价小于等于A的连下边。。
然后就出现了很多个连通块
很明显,每一个连通块只有一个地方连A就好了,然后剩下就是一个最小生成树。。
于是就AC了

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
typedef long long LL;
using namespace std;
const LL N=1005;
LL X[N],Y[N];
LL n,A,B;
struct qq
{
    LL x,y,last,z;
}s[N*N];LL num,last[N];
void init (LL x,LL y)
{
    num++;
    s[num].x=x;s[num].y=y;
    s[num].last=last[x];
    last[x]=num;
    return ;
}
bool vis[N];
bool in[N];
void dfs (LL x)
{
    if (in[x]) return ;
    vis[x]=true;in[x]=true;
    for (LL u=last[x];u!=-1;u=s[u].last)
    {
        LL y=s[u].y;
        dfs(y);
    }
}
qq e[N*N];LL num1;
void init1 (LL x,LL y,LL z)
{
    num1++;
    e[num1].x=x;e[num1].y=y;e[num1].z=z;
}
LL f[N];
bool cmp (qq a,qq b){return a.z<b.z;}
LL find (LL x){return f[x]==x?f[x]:f[x]=find(f[x]);}
LL dis (LL x,LL y)
{
    return abs(X[x]-X[y])+abs(Y[x]-Y[y]);
}
LL ans=0;
void lalal ()
{
    num1=0;
    for (LL u=1;u<=n;u++)
    {
        if (in[u]==false) continue;
        for (LL i=u+1;i<=n;i++)
            if (in[i]==true)
                init1(u,i,B*dis(u,i));
    }
/*  for (LL u=1;u<=n;u++)
        if (in[u])
            printf("%lld ",u);*/
    for (LL u=1;u<=n;u++) f[u]=u;
    sort(e+1,e+1+num1,cmp);
//  for (LL u=1;u<=num1;u++) printf("%lld %lld %lld\n",e[u].x,e[u].y,e[u].z);
    for (LL u=1;u<=num1;u++)
    {
        LL x=e[u].x,y=e[u].y;
        LL fx=find(x),fy=find(y);
        if (fx==fy) continue;
        f[fx]=fy;
        ans=ans+e[u].z;
    }
    ans=ans+A;
}
int main()
{
    freopen("diyiti.in","r",stdin);
    freopen("diyiti.out","w",stdout);
    num=0;memset(last,-1,sizeof(last));
    scanf("%lld%lld%lld",&n,&A,&B);
    for (LL u=1;u<=n;u++)   scanf("%lld%lld",&X[u],&Y[u]);
    for (LL u=1;u<=n;u++)
        for (LL i=u+1;i<=n;i++)
            if (B*dis(u,i)<=A)
            {
                init(u,i),init(i,u);
            }
    memset(vis,false,sizeof(vis));
    for (LL u=1;u<=n;u++)
    {
        memset(in,false,sizeof(in));
        if (vis[u]==true) continue;
        dfs(u);
        lalal();
    }
    printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值