bzoj4429: [Nwerc2015] Elementary Math小学数学

 

先把所有可能的答案算出来,每个算式一个点,每个结果一个点,然后如果一个算式能算出一个结果,那么就连一条边

然后跑匈牙利,没有完美匹配就是impossible

每个算式最多有3个结果,所以边数是O(n)的,所以匈牙利的复杂度就是O(n^2)的

 

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <map>
#define ll long long
#define N 77777
#define M 77777

using namespace std;
inline int read(){
	int ret=0;char ch=getchar();
	bool flag=0;
	while (ch<'0'||ch>'9'){
		flag=ch=='-';
		ch=getchar();
	}
	while ('0'<=ch&&ch<='9'){
		ret=ret*10-48+ch;
		ch=getchar();
	}
	return flag?-ret:ret;
}

struct edge{
	int adj,next,op;
	edge(){}
	edge(int _adj,int _next,int _op):adj(_adj),next(_next),op(_op){}
} e[M];
int n,g[N],m;
void AddEdge(int u,int v,int op){
	e[++m]=edge(v,g[u],op);g[u]=m;
}

int fx[N],fy[N],fop[N];
bool vis[N/3];
int dfs(int u){
	if (vis[u]) return 0;
	vis[u]=1;
	for (int i=g[u];i;i=e[i].next){
		int v=e[i].adj;
		if (!fy[v]||dfs(fy[v])){
			fy[v]=u;fx[u]=v;fop[u]=e[i].op;
			return 1;
		}
	}
	return 0;
}


char ch[3]={'+','-','*'};
inline ll calc(ll x,ll y,int op){
	if (op==0) return x+y;
	else if (op==1) return x-y;
	else return x*y;
}

ll a[N],b[N];
map<ll,int> s;int cnt;

int main(){
	n=read();
	s.clear();
	map<ll,int>::iterator it;
	ll tmp;
	for (int i=1;i<=n;++i){
		a[i]=read();b[i]=read();
		for (int op=0;op<3;++op){
			it=s.find(calc(a[i],b[i],op));
			if (it==s.end()) s.insert(make_pair(calc(a[i],b[i],op),++cnt));
			AddEdge(i,s.find(calc(a[i],b[i],op))->second,op);
		}
	}
	
	int tot=0;
	memset(fx,0,sizeof(fx));
	memset(fy,0,sizeof(fy));
	for (int i=1;i<=n;++i)if (!fx[i]){
		memset(vis,0,sizeof(vis));
		tot+=dfs(i);
	}
	if (tot<n){puts("impossible");return 0;}
	for (int i=1;i<=n;++i)
		printf("%lld %c %lld = %lld\n",a[i],ch[fop[i]],b[i],calc(a[i],b[i],fop[i]));
	return 0;
}

  

posted @ 2016-03-24 11:05  wangyurzee  阅读(237)  评论(0编辑  收藏  举报