bzoj4429 [Nwerc2015] Elementary Math小学数学 二分图

31 篇文章 0 订阅
30 篇文章 0 订阅

Description


Ellen给她的学生教小学数学。期末考试已经来临了。考试有n个题目,每一个题目学生们都要对一对数字进行加(+),减(-),乘(*)运算。
Ellen已经选好了n对数。剩下的是决定学生们应该对每对数执行什么运算。为了不让学生们感到厌烦,Ellen想确保n个正确答案都不一样。
请帮助Ellen自动化地构建考试。

第一行是一个整数n(1<=n<=2500),表示共有n道题目。
接下来n行每行有2个整数a和b(-106<=a,b<=106),表示每一题使用的整数。

对于输入中的每一对(a,b),输出一行有效的方程。每一个方程应该包含5部分:a,+、-、*中的一个运算符,b,=,答案。N个答案必须不同。
如果有多个有效答案,你可以输出任意一个。如果没有答案,输出“impossible”。

Solution


考虑以等式和运算结果建二分图,对于等式可能的结果就连边。如果匹配数=n说明有解,否则无解
dinic跑匹配好像是比匈牙利快的,但是不好搞方案

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

typedef long long LL;
const int INF=0x3f3f3f3f;
const int N=62500;
const int E=800005;

struct edge {int x,y,w,next;} e[E];
struct data {LL a,b,c,d,e;} d[N];

int dis[N],ls[N],edCnt=1;
LL b[N];

bool vis[N];

int read() {
	int x=0,v=1; char ch=getchar();
	for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
	for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
	return x*v;
}

void add_edge(int x,int y,int w) {
	e[++edCnt]=(edge) {x,y,w,ls[x]}; ls[x]=edCnt;
	e[++edCnt]=(edge) {y,x,0,ls[y]}; ls[y]=edCnt;
}

bool bfs(int st,int ed) {
	std:: queue <int> que;
	que.push(st);
	rep(i,st,ed) dis[i]=-1; dis[st]=1;
	for (;!que.empty();) {
		int now=que.front(); que.pop();
		for (int i=ls[now];i;i=e[i].next) {
			if (e[i].w>0&&dis[e[i].y]==-1) {
				dis[e[i].y]=dis[now]+1;
				if (e[i].y==ed) return true;
				que.push(e[i].y);
			}
		}
	}
	return false;
}

int find(int now,int ed,int mn) {
	if (now==ed||!mn) return mn;
	int ret=0;
	for (int i=ls[now];i;i=e[i].next) {
		if (e[i].w>0&&dis[now]+1==dis[e[i].y]) {
			int d=find(e[i].y,ed,std:: min(mn-ret,e[i].w));
			e[i].w-=d; e[i^1].w+=d; ret+=d;
			if (ret==mn) break;
		}
	}
	return ret;
}

int dinic(int st,int ed) {
	int ret=0;
	for (;bfs(st,ed);) ret+=find(st,ed,INF);
	return ret;
}

int main(void) {
	int n=read();
	rep(i,1,n) {
		d[i].a=read(),d[i].b=read();
		d[i].c=d[i].a+d[i].b;
		d[i].d=d[i].a-d[i].b;
		d[i].e=d[i].a*d[i].b;
		b[++b[0]]=d[i].c;
		b[++b[0]]=d[i].d;
		b[++b[0]]=d[i].e;
		add_edge(0,i,1);
	}
	std:: sort(b+1,b+b[0]+1);
	int size=std:: unique(b+1,b+b[0]+1)-b-1;
	rep(i,1,size) add_edge(n+i,n+size+1,1);
	rep(i,1,n) {
		d[i].c=std:: lower_bound(b+1,b+size+1,d[i].c)-b;
		d[i].d=std:: lower_bound(b+1,b+size+1,d[i].d)-b;
		d[i].e=std:: lower_bound(b+1,b+size+1,d[i].e)-b;
		add_edge(i,n+d[i].c,1);
		add_edge(i,n+d[i].d,1);
		add_edge(i,n+d[i].e,1);
	}
	if (dinic(0,n+size+1)==n) {
		rep(i,1,n) {
			for (int j=ls[i];j;j=e[j].next) {
				if (e[j].y>n&&e[j].w==0) {
					LL ans=b[e[j].y-n];
					if (ans==d[i].a+d[i].b) printf("%lld + %lld", d[i].a,d[i].b);
					else if (ans==d[i].a-d[i].b) printf("%lld - %lld", d[i].a,d[i].b);
					else if (ans==d[i].a*d[i].b) printf("%lld * %lld", d[i].a,d[i].b);
					printf(" = %lld\n", ans);
				}
			}
		}
	} else puts("impossible");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值