洛谷 P14362 题解
蓝勾曾葬送在此题上。
让你求最小生成树,我们考虑用kruskal。
但是存在新建村庄的操作。这让我们犯了难。
好消息是 \(k\le 10\),这启发着我们去枚举村庄。
枚举村庄后把与该村庄相连的边加进边集再跑kruscal,时间复杂度 \(\mathcal{O}(2^k(m+nk)\log (m+nk))\),不能通过此题。
这时我们考虑贪心。我们考虑原图最小生成树以外的边不可能作为答案,感性理解这是对的。实际上可以证明,但证明太复杂了,这里略。
于是我们将原图的边数降为了 \(n\) 数量级。时间复杂度 \(\mathcal{O}(2^k(n+nk)\log (n+nk))\),可以得 80pts。
我们可以把排序单独拎出来,在枚举之前排序,枚举时只需要从排好序的边集里取边,然后kruscal。
时间复杂度 \(\mathcal{O}((n+nk)\log (n+nk)+2^k(n+nk))\),可以通过此题。
我们自信地一交。
16pts?
蓝勾没了。
死因:没开long long。
AC code:
#include<bits/stdc++.h>
#define int long long//一定要开long long!
using namespace std;
const int M=5e6+7,N=2e4+3,INF=(1ll<<62);
struct Edge{
int u,v,w,id;
}e[M],d[M],f[M];
bool cmp(Edge x,Edge y){
return x.w<y.w;
}
int read(){
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
int fa[N];
int n,m,K,ans;
int c[11],a[11][N],b[N],st[11];
int getfa(int x){
if(x==fa[x]) return x;
return fa[x]=getfa(fa[x]);
}
void Mergeset(int x,int y){
fa[x]=getfa(x);
fa[y]=getfa(y);
fa[fa[x]]=fa[y];
}
inline void kruscal1(){
sort(e+1,e+m+1,cmp);
for(int i=1;i<=n;i++){
fa[i]=i;
}
int tot=0;
for(int i=1;i<=m;i++){
int u=e[i].u,v=e[i].v;
if(getfa(u)!=getfa(v)){
b[++tot]=i;
Mergeset(u,v);
if(tot==n-1) break;
}
}
}
inline int kruscal(int res){
if(res>=ans) return ans;
for(int i=1;i<=n+K;i++){
fa[i]=i;
}
for(int i=1;i<=m;i++){
int u=f[i].u,v=f[i].v,w=f[i].w;
if(getfa(u)!=getfa(v)){
res+=w;
if(res>=ans) return ans;
Mergeset(u,v);
}
}
if(res>=ans) return ans;
return res;
}
signed main(){
cin>>n>>m>>K;
for(int i=1;i<=m;i++)
e[i].u=read(),e[i].v=read(),e[i].w=read(),e[i].id=0;
for(int j=1;j<=K;j++){
c[j]=read();
for(int i=1;i<=n;i++){
a[j][i]=read();
}
}
kruscal1();
m=n-1;
for(int i=1;i<=n-1;i++)
d[i].u=e[b[i]].u,d[i].v=e[b[i]].v,d[i].w=e[b[i]].w,d[i].id=0;
for(int j=1;j<=K;j++){
for(int k=1;k<=n;k++)
d[++m].u=n+j,d[m].v=k,d[m].w=a[j][k],d[m].id=j;
}
sort(d+1,d+m+1,cmp);
const int U=(1<<K);
ans=INF;
st[0]=1;
for(int i=0;i<U;i++){
int res=0;
m=0;
for(int j=1;j<=K;j++)
st[j]=0;
for(int j=1;j<=K;j++){
if((1<<j-1)&i){
res+=c[j];
st[j]=1;
}
}
for(int j=1;j<=n-1+K*n;j++){
if(st[d[j].id]){
f[++m].u=d[j].u,f[m].v=d[j].v,f[m].w=d[j].w,f[m].id=d[j].id;
}
}
ans=kruscal(res);
}
cout<<ans<<'\n';
return 0;
}

浙公网安备 33010602011771号