codeforces1245D Shichikuji and Power Grid

mac2026-08-11  9

https://codeforces.com/problemset/problem/1245/D

讲讲我的思考历程

看到题目觉得是一般应该是一维DP,枚举前i个位置上一个位置选在第j号位置的最小值是多少,然而这个二维不知道怎么搞。。。

然后看了看F题感觉是个二进制下数位DP之类的,然而不太会搞,又回来想D

那么我至少要知道我要选择哪一些建电塔把,那么应该是选择代价小的电塔建立,但是这样并不一定最优,因为选择代价大一点的地方建电塔,他连线代价比较小的话,可能更优

那么是不是从连线最小的开始选择哪些连线呢?于是想到了最小生成树,n^2条边,n^2logn是可以接受的

于是我们思考连一条边会带来哪一些变化,总代价加上这条边,但是连接起来的两个联通块,只需要选择最小代价的那个店建电塔就行了。

这个方法的大致思路就出来了,按最小生成树的方式,用并查集维护一个连通块中最小的代价是哪个点,一开始没有边的代价就是所有点建电塔,每次连接一条边需要判断他能不能使得代价变小,如果能再连接这条边。

这种题还要想这么久,好菜啊.jpg,再难一点的题都不会了

 

#include<bits/stdc++.h> #define maxl 2010 using namespace std; int n,m,cnt,tot,cnt1,cnt2; int k[maxl],c[maxl],f[maxl],ans1[maxl]; long long ans; long long dis[maxl][maxl]; struct node { int x,y; }a[maxl],ans2[maxl*maxl]; char s[maxl]; struct ed { int u,v; long long w; }e[maxl*maxl]; inline void prework() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y); for(int i=1;i<=n;i++) scanf("%d",&c[i]); for(int i=1;i<=n;i++) scanf("%d",&k[i]); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) { dis[i][j]=abs(a[i].x-a[j].x)+abs(a[i].y-a[j].y); e[++cnt]=ed{i,j,dis[i][j]*(k[i]+k[j])}; } } inline int find(int x) { if(f[x]!=x) f[x]=find(f[x]); return f[x]; } inline bool cmp(const ed &a,const ed &b) { return a.w<b.w; } inline void mainwork() { for(int i=1;i<=n;i++) f[i]=i; sort(e+1,e+1+cnt,cmp); int x,y; long long tmp=0; for(int i=1;i<=n;i++) tmp+=c[i]; ans=tmp; for(int i=1;i<=cnt;i++) { x=find(e[i].u);y=find(e[i].v); if(x==y) continue; if(max(c[x],c[y])>e[i].w) { tmp=tmp-max(c[x],c[y])+e[i].w; ans2[++cnt2]=node{e[i].u,e[i].v}; if(c[x]<c[y]) f[y]=x; else f[x]=y; } ans=min(tmp,ans); } } inline void print() { for(int i=1;i<=n;i++) if(find(i)==i) ans1[++cnt1]=i; printf("%lld\n",ans); printf("%d\n",cnt1); for(int i=1;i<=cnt1;i++) printf("%d%c",ans1[i],(i==cnt1)?'\n':' '); printf("%d\n",cnt2); for(int i=1;i<=cnt2;i++) printf("%d %d\n",ans2[i].x,ans2[i].y); } int main() { int t=1; //scanf("%d",&t); for(int i=1;i<=t;i++) { prework(); mainwork(); print(); } return 0; }

 

最新回复(0)