UVALive 7427 Elementary Math(二分图)

题意:给你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]);
          }
       }
    }
}

猜你喜欢

转载自blog.csdn.net/zlatan10/article/details/81408025