Kattis Problem - Elementary Math

23 篇文章 0 订阅

Kattis Problem - Elementary Math

原题连接

题目类型:二分图最大匹配、匈牙利算法、离散化
题意

有 n 对整数,每对整数都可以使用 +、-、* 三种运算符进行运算。现在需要为每对整数选择一种运算符,并且保证最终 n 对整数的解都是不同的。

分析

对于每对数因为都有三种运算符,所以都有三个解,可以将每对数与它的解之间连一条边,则每对数与所有可能解构成一个二分图,然后就可以使用匈牙利算法来进行二分图的最大匹配。如果最后匹配了 n 个则说明存在解,然后根据匹配的结果输出每对数使用的运算符,否则无解。因为操作数比较大,所有要先离散化一下。

代码
static Node[] a;
static boolean[] vis;
static int[] match;
static int[] res;
static long[] all;
static int aLen;

public static void solve() throws IOException {
    int n = nextInt();
    
    init(n);
    
    for (int i = 1; i <= n; i++) {
        a[i] = new Node(nextInt(), nextInt());
        all[aLen++] = a[i].add();
        all[aLen++] = a[i].str();
        all[aLen++] = a[i].mul();
    }
    
    unique();
    

    for (int i = 1; i <= n; i++) {
        a[i].to[0] = getAim(all, 1, aLen - 1, a[i].add());
        a[i].to[1] = getAim(all, 1, aLen - 1, a[i].str());
        a[i].to[2] = getAim(all, 1, aLen - 1, a[i].mul());
    }
    
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j < aLen; j++) vis[j] = false;
        if (Hungary(i)) ans++;
    }
    
    if (ans != n) pw.println("impossible");
    else {
        for (int i = 1; i <= n; i++) {
            char op = '-';
            if (all[res[i]] == a[i].add()) op = '+';
            if (all[res[i]] == a[i].str()) op = '-';
            if (all[res[i]] == a[i].mul()) op = '*';
            pw.println(a[i].x + " " + op + " " + a[i].y + " = " + all[res[i]]);
        }
    }
}   


public static boolean Hungary(int x) {
    for (int i = 0; i < 3; i++) {
        int e = a[x].to[i];
        if (!vis[e]) {
            vis[e] = true;
            if (match[e] == 0 || Hungary(match[e])) {
                match[e] = x;
                res[x] = e;
                return true;
            }
        }
    }
    
    return false;
}


public static int getAim(long[] a, int l, int r, long aim) {
    while (l < r) {
        int mid = l + r >> 1;
        if (a[mid] >= aim) r = mid;
        else l = mid + 1;
    }
    return r;
}

public static void unique() {
    Arrays.sort(all, 1, aLen);
    
    int q = 2, p = 2;
    while (p < aLen) {
        if (all[q - 1] != all[p]) all[q++] = all[p];
        p++;
    }
    aLen = q;
}

public static void init(int n) {
    a = new Node[n + 1];
    res = new int[n * 3 + 1];
    match = new int[n * 3 + 1];
    vis = new boolean[n * 3 + 1];
    all = new long[n * 3 + 1];
    aLen = 1;
}

/*******************************************************************************************************************************/

static class Node {
    int x, y;
    int[] to;
    
    public Node(int x, int y) {
        // TODO Auto-generated constructor stub
        this.x = x;
        this.y = y;
        to = new int[3];
    }
    
    public int add() { return x + y; }
    
    public int str() { return x - y; }
    
    public long mul() { return (long) x * y; }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值