当前位置:   article > 正文

AtCoder Beginner Contest 263 G.Erasing Prime Pairs(二分图最大匹配-网络流)_atcode 二分图匹配

atcode 二分图匹配

题目

黑板上有n(n<=100)个不同的数,第i个数ai(1<=ai<=1e7)出现了bi(1<=1e9)次,

你每次可以选择当前黑板上存在的两个数x、y,满足x+y是质数,擦掉这两个数,

求可以擦掉的最大次数

思路来源

AtCoder Beginner Contest 题目选解 - 云浅知处 - 博客园

题解

先考虑a,b,c互不相同的情形,三个素数里面必有至少两个数是奇素数,

不妨a+b和a+c是奇数,则b和c同奇偶,b+c之和必为偶数,b不等于c则b+c不等于2,

所以b+c不为素数,原图是一个近似二分图的图,

但是,注意到b=c=1的时候,例如a=4,b=c=1,两两匹配也均为素数

自己wa的过程和思路来源基本一模一样,所以直接粘过来了…

考虑原图除了1以外,其余部分都是二分图,1和1自己能构成素数2,有一个自环

所以考虑把1拆成2个点,入点和出点,再连边,答案就对了

无向图最大匹配拆入点和出点,答案需要除以2这个也是典中典了…

代码

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int INF=0x3f3f3f3f;
  5. const int maxn=210,N=maxn;
  6. const int maxm=maxn*maxn*5+10,M=2e7+10;
  7. int level[maxn];
  8. int head[maxn],cnt;
  9. int t,n,m,a[N],b[N],col[N],to[N];
  10. int ss,ee;
  11. bool ok[M];
  12. int prime[M],tot;
  13. struct edge{int v,nex;ll w;}e[maxm];
  14. void init()
  15. {
  16. cnt=0;
  17. memset(head,-1,sizeof head);
  18. }
  19. void add(int u,int v,ll w)
  20. {
  21. e[cnt].v=v;
  22. e[cnt].w=w;
  23. e[cnt].nex=head[u];
  24. head[u]=cnt++;
  25. }
  26. void add2(int u,int v,ll w,bool op)//是否为有向图
  27. {
  28. add(u,v,w);
  29. add(v,u,op?0:w);
  30. }
  31. bool bfs(int s,int t)
  32. {
  33. queue<int>q;
  34. memset(level,0,sizeof level);
  35. level[s]=1;
  36. q.push(s);
  37. while(!q.empty())
  38. {
  39. int x=q.front();
  40. q.pop();
  41. if(x==t)return 1;
  42. for(int u=head[x];~u;u=e[u].nex)
  43. {
  44. int v=e[u].v;ll w=e[u].w;
  45. if(!level[v]&&w)
  46. {
  47. level[v]=level[x]+1;
  48. q.push(v);
  49. }
  50. }
  51. }
  52. return 0;
  53. }
  54. ll dfs(int u,ll maxf,int t)
  55. {
  56. if(u==t)return maxf;
  57. ll ret=0;
  58. for(int i=head[u];~i;i=e[i].nex)
  59. {
  60. int v=e[i].v;ll w=e[i].w;
  61. if(level[u]+1==level[v]&&w)
  62. {
  63. ll MIN=min(maxf-ret,w);
  64. w=dfs(v,MIN,t);
  65. e[i].w-=w;
  66. e[i^1].w+=w;
  67. ret+=w;
  68. if(ret==maxf)break;
  69. }
  70. }
  71. if(!ret)level[u]=-1;//优化,防止重搜,说明u这一路不可能有流量了
  72. return ret;
  73. }
  74. ll Dinic(int s,int t)
  75. {
  76. ll ans=0;
  77. while(bfs(s,t))
  78. ans+=dfs(s,INF,t);
  79. return ans;
  80. }
  81. void sieve()
  82. {
  83. for(ll i=2;i<M;++i)
  84. {
  85. if(!ok[i])prime[tot++]=i;
  86. for(int j=0;j<tot;++j)
  87. {
  88. if(i*prime[j]>=M)break;
  89. ok[i*prime[j]]=1;
  90. if(i%prime[j]==0)break;
  91. }
  92. }
  93. }
  94. int main(){
  95. init();
  96. sieve();
  97. scanf("%d",&n);
  98. for(int i=1;i<=n;++i){
  99. scanf("%d%d",&a[i],&b[i]);
  100. }
  101. ss=2*n+1;ee=2*n+2;
  102. for(int i=1;i<=n;++i){
  103. add2(ss,i,b[i],1);
  104. add2(i+n,ee,b[i],1);
  105. for(int j=1;j<=n;++j){
  106. if(!ok[a[i]+a[j]]){
  107. add2(i,j+n,min(b[i],b[j]),1);
  108. add2(j,i+n,min(b[i],b[j]),1);
  109. }
  110. }
  111. }
  112. ll ans=Dinic(ss,ee);
  113. printf("%lld\n",ans/2);
  114. return 0;
  115. }
  116. //1 6 7 12

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/281710?site
推荐阅读