bzoj3714: [PA2014]Kuglarz题解

bzoj3714: [PA2014]Kuglarz题解

原题链接:

妥妥的神题,

看到这道题谁会想到最小生成树,

而且kruskal还很难卡过去,即使有20s(人丑自带常数大

只好又学了一波prim,

感觉还行,跟dijkstra差不多???~~~

所以代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5006,M=200006;
int n,m,cnt=0,p=0,t1,t2,t3,dis[N],v[N],head[N];
ll sum=0;
struct edge{int nxt,to,w;}e[M<<1];
struct xd{
   int z,i;
   bool operator < (const xd &a) const {return a.z<z;}
}tmp,nw;
priority_queue<xd> q;
inline void add(int u,int v,int w){e[++cnt].nxt=head[u],e[cnt].to=v,e[cnt].w=w,head[u]=cnt;}
void prim(){
    memset(dis,0x7f,sizeof(dis));
    dis[1]=0,tmp.z=0,tmp.i=1,q.push(tmp);
    while(!q.empty()){
       tmp=q.top(),q.pop();
       if(v[tmp.i]) continue;
       v[tmp.i]=1,++p,sum+=tmp.z;
       for(int i=head[tmp.i];i;i=e[i].nxt) if(dis[e[i].to]>e[i].w) dis[e[i].to]=e[i].w,nw.i=e[i].to,nw.z=e[i].w,q.push(nw);
    } 
}
inline int read(){
   int T=0,F=1; char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
   while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
   return F*T;
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=m;++i) t1=read(),t2=read(),t3=read(),add(t1,t2,t3),add(t2,t1,t3);
    prim();
    if(p<n) printf("orz\n");
    else printf("%lld\n",sum);
    return 0;
} 

好了好了,下面就来分析分析这一道题,出(sang)得(xin)真(bin)好(kuang):

\(S_{i}\)为第\(1\)个到第\(i\)个杯子下球的个数的奇偶性,

那么,第\(l\)个杯子到第\(r\)个杯子的奇偶性为\(S_{l-1}\)^\({S_{r}}\)

所以我们从\(l-1\)\(r\)连一条权值为\(c_{l,r}\)的边,代表若知道\(l\)或者\(r\)的奇偶性,花费\(c_{l,r}\)可以知道另一个的奇偶性。

最后,我们要知道所有点的权值,只要确保图的连通即可(0点的奇偶性为0),用最小生成树求出最小代价。

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5006,M=4000006;
int n,m,cnt=0,p=0,t1,t2,t3,dis[N],v[N],head[N];
ll sum=0;
struct edge{int nxt,to,w;}e[M<<1];
struct xd{
   int z,i;
   bool operator < (const xd &a) const {return a.z<z;}
}tmp,nw;
priority_queue<xd> q;
inline void add(int u,int v,int w){e[++cnt].nxt=head[u],e[cnt].to=v,e[cnt].w=w,head[u]=cnt;}
void prim(){
    memset(dis,0x7f,sizeof(dis));
    dis[0]=0,tmp.z=0,tmp.i=0,q.push(tmp);
    while(!q.empty()){
       tmp=q.top(),q.pop();
       if(v[tmp.i]) continue;
       v[tmp.i]=1,++p,sum+=tmp.z;
       for(int i=head[tmp.i];i;i=e[i].nxt) if(!v[e[i].to]&&dis[e[i].to]>e[i].w) dis[e[i].to]=e[i].w,nw.i=e[i].to,nw.z=e[i].w,q.push(nw);
    } 
}
inline int read(){
   int T=0,F=1; char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
   while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
   return F*T;
}
int main(){
    n=read();
    for(int i=1;i<=n;++i) for(int j=i;j<=n;++j) t1=read(),add(i-1,j,t1),add(j,i-1,t1);
    prim(),printf("%lld\n",sum);
    return 0;
} 

转载于:https://www.cnblogs.com/ljk123-de-bo-ke/p/11323331.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值