题意:给你n对二元操作数,可以对任意一对操作数进行 + 、- 、* 三种中的任意一种操作,组成一个算式。要求最后这n个算式得到的n个答案没有重复的,问是否可能,可能则输出方法,否则输出impossible。
分析:每个一对操作数能进行算种操作,一开始想能不能看每个答案被访问了几次然后乱搞一下,但是没有什么办法。就感觉是一个二分图匹配问题,将操作数对和答案之间连边,然后跑一个匈牙利,就过了。因为答案会有负数,也有可能超出int表示范围,但考虑到最多只有2500个算式,7500个答案,所以没有离散化了感觉太麻烦而且没必要,直接使用map存储状态。
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<map>
#include<queue>
#define ll long long
#define inf 0x7ffffff
using namespace std;
typedef pair<ll,ll>pll;
map<ll,int>use;
map<ll,ll>girl;
const int N = 2500 +5;
ll a[N],b[N];
ll ans[N];
char s[N];
int n;
bool solve(int x)
{
ll tem[4];
tem[0] = a[x] * b[x];
tem[1] = a[x] + b[x];
tem[2] = a[x] - b[x];
for(int i = 0; i < 3; i++)
{
ll now = tem[i];
if(use[now] == 1) continue;
use[now] = 1;
if(girl[now] == -1 || solve(girl[now]))
{
girl[now] = x;
ans[x] = now;
if(i == 0) s[x] = '*';
else if(i == 1) s[x] = '+';
else s[x] = '-';
return 1;
}
}
return 0;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i = 0; i < n; i++)
{
scanf("%lld%lld",&a[i],&b[i]);
ll mul = a[i] * b[i];
ll sum = a[i] + b[i];
ll sub = a[i] - b[i];
girl[mul] = -1;
girl[sum] = -1;
girl[sub] = -1;
}
int fl = 0;
for(int i = 0; i < n; i++)
{
use.clear();
if(!solve(i))
{
fl = 1;
break;
}
}
if(fl) printf("impossible\n");
else
{
for(int i = 0; i < n; i++)
{
printf("%lld %c %lld = %lld\n",a[i],s[i],b[i],ans[i]);
}
}
}
}