Bzoj2661--Wc2012连连看
暴力预处理出可行点对,拆点后跑最小费用最大流,费用取负
连边要对连,就是x->y和y->x都要连,最后除2才是答案
因为这里每个数只能匹配一次,对连的话同一个点两边都会采用同样的连法所以可以避免多次匹配
代码:
#include<bits/stdc++.h> #define INF 1000000000 using namespace std; inline double _fabs(double a) {return a>0?a:-a;} inline int read() { int ret=0,f=1;char c=getchar(); while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();} while(c<='9'&&c>='0') {ret=ret*10+c-'0';c=getchar();} return ret*f; } inline int gcd(int a,int b) { int t; while(b) {t=a;a=b;b=t%b;} return a; } #define fix 1000 #define MAXN 2005 #define MAXM 10005 const int S=2002,T=2003; int L,R; int head[MAXN],cnt=1; struct Edge{ int to,flow,cap,next,cost,from; }e[MAXM]; inline void insert(int a,int b,int f,int c) { e[++cnt].next=head[a];head[a]=cnt;e[cnt].to=b;e[cnt].flow=f;e[cnt].cap=0;e[cnt].cost=c;e[cnt].from=a; e[++cnt].next=head[b];head[b]=cnt;e[cnt].to=a;e[cnt].flow=0;e[cnt].cap=0;e[cnt].cost=-c;e[cnt].from=b; } queue<int> q;int z[MAXN],bk[MAXN];bool f[MAXN]; int updata(){ int a=INF; for(int i=bk[T];i;i=bk[e[i].from]) { a=min(a,e[i].flow-e[i].cap); } for(int i=bk[T];i;i=bk[e[i].from]) { e[i].cap+=a;e[i^1].cap-=a; } return a; } int fw,ct; int spfa() { int k;memset(z,0x3f3f,sizeof(z)); q.push(S);z[S]=0;f[S]=1; while(!q.empty()) { k=q.front();q.pop(); for(int i=head[k];i;i=e[i].next) { if(z[e[i].to]>z[k]+e[i].cost&&e[i].flow>e[i].cap) { bk[e[i].to]=i;z[e[i].to]=e[i].cost+z[k]; if(!f[e[i].to]){q.push(e[i].to);f[e[i].to]=1;} } } f[k]=0; } if(z[T]<0x3f3f3f3f) k=updata(); else k=0;ct+=k*z[T]; return k; } void MSMF() { int f; while(f=spfa()) fw+=f; } int main() { L=read();R=read(); for(int w,t,i=L;i<R;i++) for(int j=i+1;j<=R;j++) { w=j*j-i*i;t=sqrt(w); if(t*t==w&&gcd(i,t)==1) { insert(i,j+fix,1,-i-j); insert(j,i+fix,1,-i-j); } } for(int i=L;i<=R;i++) {insert(S,i,1,0);insert(i+fix,T,1,0);} MSMF(); printf("%d %d\n",fw/2,-ct/2); return 0; }