[BZOJ2661][BeiJing wc2012]连连看 费用流

2661: [BeiJing wc2012]连连看

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1349  Solved: 577
[Submit][Status][Discuss]

Description

 凡是考智商的题里面总会有这么一种消除游戏。不过现在面对的这关连连看可不是QQ游戏里那种考眼力的游戏。我们的规则是,给出一个闭区间[a,b]中的全部整数,如果其中某两个数x,y(设x>y)的平方差x2-y2是一个完全平方数z2,并且y与z互质,那么就可以将x和y连起来并且将它们一起消除,同时得到x+y点分数。那么过关的要求就是,消除的数对尽可能多的前提下,得到足够的分数。快动手动笔算一算吧。

Input

        
 只有一行,两个整数,分别表示a,b。

Output

 两个数,可以消去的对数,及在此基础上能得到的最大分数。

Sample Input

1 15

Sample Output

2 34

HINT

 

对于30%的数据,1<=a,b<=100

对于100%的数据,1<=a,b<=1000

 

Source

 

拆点直接连边。跑最大费用最大流,答案/2。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<cstdio>
 6 #include<algorithm>
 7 using namespace std;
 8 struct data {
 9     int cost,w,to,next;
10 }e[100000];
11 int head[10000],cnt;
12 int S,T; 
13 void add(int u,int v,int w,int c) {
14     e[cnt].to=v;e[cnt].next=head[u];e[cnt].w=w;e[cnt].cost=c;head[u]=cnt++;
15     e[cnt].to=u;e[cnt].next=head[v];e[cnt].w=0;e[cnt].cost=-c;head[v]=cnt++;
16 }
17 int dis[10000];
18 bool vis[10000];
19 int q[10000],used;
20 bool spfa() {
21     memset(dis,-37,sizeof(dis));
22     vis[T]=1;dis[T]=0;
23     int h=0,t=1;
24     q[0]=T;
25     while(h!=t) {
26         int now=q[h];h++;if(h==10000) h=0;
27         for(int i=head[now];i>=0;i=e[i].next) {
28             int to=e[i].to;if(!e[i^1].w) continue;
29             if(dis[to]<dis[now]-e[i^1].cost) {
30                 dis[to]=dis[now]-e[i^1].cost;
31                 if(!vis[to]) {vis[to]=1;q[t++]=to;if(t==10000)t=0;}
32             }
33         }
34         vis[now]=0;
35     }
36     used=-dis[S];
37     return dis[S]!=dis[9999];
38 }
39 int ans=0;
40 int dfs(int x,int a) {
41     if(x==T) {ans+=used*a;return a;} 
42     int f=0,flow=0;vis[x]=1;
43     for(int i=head[x];i>=0;i=e[i].next) {
44         int to=e[i].to;
45         if(!vis[to]&&e[i].w>0&&dis[to]==dis[x]+e[i].cost&&(f=dfs(to,min(e[i].w,a)))) {
46             e[i].w-=f;e[i^1].w+=f;
47             a-=f;flow+=f;
48             if(a==0) break;
49         }
50     }
51     return flow;
52 }
53 void zkw() {
54     while(spfa()) {
55         do {
56             memset(vis,0,sizeof(vis));
57         }while(dfs(S,2147483647));
58         memset(vis,0,sizeof(vis));
59     }
60 }
61 bool check(int x,int y) {
62     int tmp=x*x-y*y,z=(int)sqrt(tmp);  
63     if (z*z!=tmp) return false;  
64     if (y<z) swap(y,z);  
65     while (z){tmp=y%z;y=z;z=tmp;}  
66     return (y==1);  
67 }  
68 int main() {
69     memset(head,-1,sizeof(head));
70     int a,b;
71     scanf("%d%d",&a,&b);
72     S=2001;T=2002;  
73     for(int i=a;i<=b-1;i++) 
74         for(int j=i+1;j<=b;j++) if (check(j,i)) {  
75             add(i,j+1000,1,-i-j);
76             add(j,i+1000,1,-i-j);  
77         }  
78     for(int i=a;i<=b;i++) {  
79         add(S,i,1,0);  
80         add(i+1000,T,1,0);  
81     }
82     zkw();
83     int tot=0;
84     for(int i=0;i<cnt;i++) if (e[i].to==T&&!e[i].w) tot++;  
85     printf("%d %d\n",tot/2,-ans/2);  
86 }
View Code

 

转载于:https://www.cnblogs.com/wls001/p/8416779.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值