CodeForces 1245D Shichikuji and Power Grid

cf题面

解题思路

比赛过程中想了一个贪心——把所有城市按照自建代价排序,排在第一的城市肯定自建,之后依次判断排在后面的城市要自建还是要连接前面的。这么做WA13了(第一次忘开long longWA4)。

赛后看看题解,又参考了之前同样WA13的 Artoriax的代码,大概发现了这种做法的漏洞。假设自建代价是\(c_1<c_2<c_3\),可以构造连边的代价,使得在花费最小的连接方式中,连边应该是1—3—2,我之前那样的做法,1号城市自建以后,判断2号城市要自建还是要连1号城市,再判断3号城市要自建还是要连1号城市或者2号城市。

具体的hack数据如下——

3
1 1
2 2
2 1
1 5 100
1 2 1

说简单点大概就是,1、2、3自建代价是1、5、100,1到2连边代价是5,1到3的连边代价是2,2到3的连边代价是3。最小代价答案是6,我那种方法跑出来是8。

我后来AC的思路大概是:首先假设每个点都自建,那么每个点的代价就是自建代价。然后按照代价排序,用代价最小的点去更新后面那些点,如果能更新用电代价,就把那些点连接到当前点。然后进入下一轮循环,排除上一次代价最小的点,把剩下的点再次按照代价排序,然后用这些点中代价最小的去更新其他的,以此类推。

官方题解还提供了一种更一般的想法:这题其实就是求一个最小生成树,图是这么建的——首先所有点之间连边,边权就是连接代价,然后加一个0号点,所有点向0号点连边,边权是自建代价。这么一想,我AC的思路就是毫无堆优化的、还不如线性直接找最小值的、很蠢的Prim了。

源代码

#include<cstdio>
#include<algorithm>
int n;
struct City{
    int id;
    long long x,y;
    long long cc,kk;
    bool self;
    int fa;
    bool operator < (const City & a)const{
        return cc<a.cc;
    }
}c[2005];
int main()
{
    // freopen("test.in","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        c[i].id=i;
        c[i].self=1;
        scanf("%lld%lld",&c[i].x,&c[i].y);
    }
    for(int i=1;i<=n;i++) scanf("%lld",&c[i].cc);
    for(int i=1;i<=n;i++) scanf("%lld",&c[i].kk);
    long long ans=0,selfnum=0;
    for(int i=1;i<=n;i++)
    {
        std::sort(c+i,c+1+n);//大概就是要随时排序,每次找到最小的
        ans+=c[i].cc;
        if(c[i].self) selfnum++;
        for(int j=i+1;j<=n;j++)
        {
            long long cost=(c[i].kk+c[j].kk)*(std::abs(c[i].x-c[j].x)+std::abs(c[i].y-c[j].y));
            if(cost<c[j].cc)
            {
                c[j].cc=cost;
                c[j].self=0;//放弃自建
                c[j].fa=c[i].id;
            }
        }
    }
    printf("%lld\n%lld\n",ans,selfnum);
    for(int i=1;i<=n;i++)
        if(c[i].self) printf("%d ",c[i].id);
    printf("\n%lld\n",n-selfnum);
    for(int i=1;i<=n;i++)
        if(!c[i].self) printf("%d %d\n",c[i].id,c[i].fa);
    return 0;
}

原文地址:https://www.cnblogs.com/wawcac-blog/p/11782467.html

时间: 2024-10-08 09:34:20

CodeForces 1245D Shichikuji and Power Grid的相关文章

Shichikuji and Power Grid

D. Shichikuji and Power Grid 参考:Codeforces Round #597 (Div. 2) 思路:一个很裸的最小生成树.把建立基站看成是,城市与源点(虚构的)建边.由此建立最小生成树,即可得出答案. 代码: // Created by CAD on 2019/11/2. #include <bits/stdc++.h> #define ll long long #define pii pair<int,int> using namespace st

CF1245D: Shichikuji and Power Grid

CF1245D: Shichikuji and Power Grid 题意描述: 给定\(n\)个点\((n\leq2000)\),在第\(i\)个点上建立一个基站需要\(c_i\)的代价,连接两个点需要\((|x_i-x_j|+|y_i-y_j|)*(k_i+k_j)\)的代价.对于一个点要么建立基站,要么连接建立基站的点.问最小代价是多少,同时输出建立基站的点和线路. 思路: 建立一个超级根,对于每个城市建立发电站,连接一条权值为\(c_i\)的边,再把每个城市之间连接电线的花费算出来,跑\

Codeforces Round #597 (Div. 2) D. Shichikuji and Power Grid

题意: 二维平面上n个点,每个点可以建厂,也可以与其他点连边,建厂花费为\(c_i\),与j连边花费为\((k_i+k_j)*dis(i,j)\),dis为两点之间的欧式距离,求让每个点都通电的最小花费与方案 思路: 维护使这个点通电的花费的优先队列,一开始先把建厂放进去,然后每次拿出最小花费的点i,再用i去更新与i建路的花费(有点像最小生成树). #include<bits/stdc++.h> #define ll long long #define pii pair<int,int&

codeforces Codeforces Round #597 (Div. 2) D. Shichikuji and Power Grid

#include<bits/stdc++.h> using namespace std ; int n; struct City { int id; long long x,y; //坐标 long long cc,kk; //自建的花费,连线的花费 bool self;//是否建站 int fa;//连线的站 bool operator < (const City & a)const { return cc<a.cc; } } c[2005]; int main() {

[Codeforces 1228E]Another Filling the Grid (排列组合+容斥原理)

[Codeforces 1228E]Another Filling the Grid (排列组合+容斥原理) 题面 一个\(n \times n\)的格子,每个格子里可以填\([1,k]\)内的整数.要保证每行每列的格子上的数最小值为1,有多少种方案 \(n \leq 250,k \leq 10^9\) 分析 这题有\(O(n^3)\)的dp做法,但个人感觉不如\(O(n^2 \log n)\)直接用数学方法求更好理解. 考虑容斥原理,枚举有\(i\)行最小值>1,有\(j\)行最小值>1,那

【CodeForces】906 D. Power Tower 扩展欧拉定理

[题目]D. Power Tower [题意]给定长度为n的正整数序列和模数m,q次询问区间[l,r]累乘幂%m的答案.n,q<=10^5,m,ai<=10^9. [算法]扩展欧拉定理 [题解]扩展欧拉定理的形式: $$a^b\equiv a^{b\%\varphi(p)+\varphi(p)} \ \ mod \ \ p \ \ (b\leq \varphi(p))$$ 特别注意当b<φ(p)且(a,p)≠1时不变. 假如现在是三个累乘幂a^(b^c),那么根据扩展欧拉定理: $$a^

codeforces 680E Bear and Square Grid 巧妙暴力

这个题是个想法题 先预处理连通块,然后需要用到一种巧妙暴力,即0变1,1变0,一列列添加删除 复杂度O(n^3) #include <cstdio> #include <iostream> #include <ctime> #include <vector> #include <cmath> #include <map> #include <queue> #include <algorithm> #includ

codeforces 356C Bear and Square Grid

#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> using namespace std; char mp[510][510]; int vis[510][510]; int are_num[510][510]; int sum[510][510]; int

Codeforces 1228E. Another Filling the Grid

传送门 看到 $n=250$ 显然考虑 $n^3$ 的 $dp$ 设 $f[i][j]$ 表示填完前 $i$ 行,目前有 $j$ 列的最小值是 $1$ 的合法方案数 那么对于 $f[i][j]$ ,枚举 $f[i-1][k]$ ,有 $f[i][j]=\sum_{k=0}^{j}\binom{n-k}{j-k}f[i-1][k](m-1)^{n-j}m^k$ 这里 $m$ 就是题目的 $k$ $\binom{n-k}{j-k}$ 是因为多出来的 $j-k$ 列 $1$ 可以任选 $(m-1)^{