BZOJ 2661 [BeiJing wc2012]连连看 费用流

[BeiJing wc2012]连连看

题目连接:

http://www.lydsy.com/JudgeOnline/problem.php?id=2661

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

1<=a,b<=1000

题意

题解:

费用流的水题,如果i,j之间能够删去的话,就S-i-j-T,费用为(-i-j),流量为1

你会发现是个二分图的模型。

如果流经过了i到达j的话,那么j也会显然选择i的,所以最后答案要除以2.

代码

#include<bits/stdc++.h>
using namespace std;

struct ZKW_MinCostMaxFlow{

    const static int maxn = 1e5 + 50;
    const static int maxE = 1e5 + 50;
    const static int INF = 0x3f3f3f3f;

    struct Edge{
        int to,next,cap,flow,cost;
        Edge(int _to=0,int _next=0,int _cap=0,int _flow=0,int _cost=0):
            to(_to),next(_next),cap(_cap),flow(_flow),cost(_cost){}
    }edge[maxE * 2];

    int head[maxn],tot;
    int cur[maxn];
    int dis[maxn];
    bool vis[maxn];
    int ss,tt,N;
    int min_cost,max_flow;
    void init(int N){
        tot=0;
        for( int i = 0 ; i < N ; ++ i ) head[i] = -1;
    }
    int addedge(int u,int v,int cap,int cost){
        edge[tot]=Edge(v,head[u],cap,0,cost);
        int rs = tot;
        head[u]=tot++;
        edge[tot]=Edge(u,head[v],0,0,-cost);
        head[v]=tot++;
        return rs;
    }
    int aug(int u,int flow){
        if(u==tt) return flow;
        vis[u]=true;
        for(int i=cur[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if( edge[i].cap>edge[i].flow && !vis[v] && dis[u]==dis[v]+edge[i].cost ){
                int tmp=aug(v,min(flow,edge[i].cap-edge[i].flow));
                edge[i].flow+=tmp;
                edge[i^1].flow-=tmp;
                cur[u]=i;
                if(tmp) return tmp;
            }
        }
        return 0;
    }
    bool modify_label(){
        int d=INF;
        for(int u=0;u<N;u++){
            if(vis[u])
            for(int i=head[u];i!=-1;i=edge[i].next){
                int v=edge[i].to;
                if(edge[i].cap>edge[i].flow && !vis[v])
                    d=min(d,dis[v]+edge[i].cost-dis[u]);
            }
        }
        if(d==INF) return false;
            for(int i=0;i<N;i++)
            if(vis[i]){
                vis[i]=false;
                dis[i]+=d;
            }
        return true;
    }
    pair < int , int > mincostmaxflow(int start,int ed,int n ){
        ss=start,tt=ed,N=n;
        min_cost=max_flow=0;
        for(int i=0;i<n;i++) dis[i]=0;
        while(1){
            for(int i=0;i<n;i++) cur[i]=head[i];
            while(1){
                for(int i=0;i<n;i++) vis[i]=false;
                int tmp=aug(ss,INF);
                if(tmp==0) break;
                max_flow+=tmp;
                min_cost+=tmp*dis[ss];
            }
            if(!modify_label()) break;
        }
        return make_pair( max_flow , min_cost );
    }
}solver;
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
bool check(int a,int b){
    if(a==b)return false;
    if(a<b)swap(a,b);
    int t = sqrt(a*a-b*b);
    if(t*t!=a*a-b*b)return false;
    if(gcd(b,t)!=1)return false;
    return true;
}
int main(){
    int a,b;
    scanf("%d%d",&a,&b);
    solver.init(b*2+5);
    for(int i=a;i<=b;i++){
        for(int j=a;j<=b;j++){
            if(check(i,j)){
                solver.addedge(i,j+b,1,-i-j);
            }
        }
        solver.addedge(b*2+1,i,1,0);
        solver.addedge(i+b,b*2+2,1,0);
    }
    pair<int,int>ans=solver.mincostmaxflow(b*2+1,b*2+2,b*2+5);
    printf("%d %d\n",ans.first/2,-ans.second/2);
}
posted @ 2017-03-27 20:04  qscqesze  阅读(372)  评论(0编辑  收藏  举报