Gym 101485E Elementary Math (离散 + 二分图匹配)

本文探讨了如何通过算法自动化创建一份确保所有答案各不相同的数学考试,涉及到二分图匹配和最大流算法的应用,以及如何处理大规模数据的离散化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem E Elementary Math Time limit: 10 seconds

Example exam by Ellen Ellen is teaching elementary math to her students and the time for the final exam has come. The exam consists of n questions. In each question the students have to add (+), subtract (−) or multiply (∗) a pair of numbers. Ellen has already chosen the n pairs of numbers. All that remains is to decide for each pair which of the three possible operations the students should perform. To avoid students getting bored, Ellen wants to make sure that the n correct answers to her exam are all different. Please help Ellen finish constructing the exam by automating this task.

Input The input consists of: • one line with one integer n (1 ≤ n ≤ 2 500), the number of pairs of numbers; • n lines each with two integers a and b (−106 ≤ a, b ≤ 106 ), a pair of numbers used.

Output For each pair of numbers (a, b) in the same order as in the input, output a line containing a valid equation. Each equation should consist of five parts: a, one of the three operators, b, an equals sign (=), and the result of the expression. All the n expression results must be different. If there are multiple valid answers you may output any of them. If there is no valid answer, output a single line with the string “impossible” instead.

题意:给你一个数 N, 然后下面有 N 对数,每对数可以进行 + - * 操作,每对数选择一个结果,是不是存在每对数选择的结果都不一样。如果是,把每对数选择的结果写下来,并记录下是什么操作,如果不行,就输出 impossible。

思路: 这个题看着就是一个二分图匹配问题。如果能够匹配上 N 个,说明就行。

由于数很大,我们要离散化。

当然,这个是二分图匹配,我们也可以用 最大流 来做。

这个题我 WA 的原因是,最后判断输出的时候,条件没有写完全,

少写了 else , 有可能存在 两个数 的 ( 加 减  乘 ) 得出的结果是一样的,这样的情况我没有考虑。

 

#include <bits/stdc++.h>
using namespace std;
#define mem(x,v) memset(x,v,sizeof(x))
const int N = 10000;
struct edge{
    int v,next;
}ed[N];
int cnt = -1;
int head[N];
struct node{
    int a;
    long long b;
    bool operator < (const node &now) const {
        return b < now.b;
    }
}f[N];
int d[N],linker[N];
long long x[N],y[N];
long long c[N];
bool vis[N];
int n,t = 0;
void Add(int u, int v){
    cnt++;
    ed[cnt].next = head[u];
    head[u] = cnt;
    ed[cnt].v = v;
    return;
}

bool dfs(int u){
    for (int i = head[u]; i != -1; i = ed[i].next){
        int v = ed[i].v;
        if (!vis[v]){
            vis[v] = 1;
            if (linker[v] == -1 || dfs(linker[v])){
                linker[v] = u;
                return 1;
            }
        }
    }
    return 0;
}
int big_matching(){
    int ans = 0;
    mem(linker,-1);
    for (int i = 0; i <= t; i++){
        mem(vis,0);
        if (dfs(i)) ans++;
    }
    return ans;
}
int main() {
    scanf("%d",&n);
    for (int i = 0; i < n; i++){
        scanf("%I64d%I64d",&x[i],&y[i]);
        f[i*3+0].b = x[i] + y[i];
        f[i*3+1].b = x[i] - y[i];
        f[i*3+2].b = x[i] * y[i];
        f[i*3+0].a = i*3+0;
        f[i*3+1].a = i*3+1;
        f[i*3+2].a = i*3+2;
    }
    sort(f,f+3*n);
    //for (int i = 0;i < 3*n; i++)
      //  printf("%d %d\n",f[i].a, f[i].b);
    c[0] = f[0].b; //离散化之后的值向原来值得映射。
    d[f[0].a] = 0; //在原来的位置上放上离散化的值。
    for (int i = 1; i < 3 * n; i++){
        if (f[i].b != f[i - 1].b) {
            t++;
            c[t] = f[i].b;
        }
        d[f[i].a] = t;
    }
    //for (int i = 0; i < 3*n; i++)
//        printf("%d %d\n",d[i],c[d[i]]);
    mem(head,-1);
    for (int i = 0; i < 3 * n; i++){
        Add(d[i],i/3);
    }
    int Ans = big_matching();
   // cout<<Ans<<endl;
    if (Ans != n) printf("impossible\n"); else {
        for (int i = 0; i < n; i++){
            long long tt = c[linker[i]];
            printf("%I64d ",x[i]);
            if (x[i] + y[i] == tt) printf("+ "); else //少写了 else 一直 WA ,
            if (x[i] - y[i] == tt) printf("- "); else
            if (x[i] * y[i] == tt) printf("* ");
            printf("%I64d = %I64d\n",y[i],tt);
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值