XTU-OJ 1408-Cow

题目描述

农夫约翰有一个农场,他把上面分成了n×m个格子,每个格子里养了一头牛。 但是有p对相邻格子(有共同边的格子)的牛是敌对关系,喜欢打架,约翰想做一些栅栏把他们分开。 所有的栅栏都是沿着边线的,横的或者竖的,每条栅栏都是贯穿整个横边或者竖边的。 但是约翰的预算有限,他想知道最多建k条栅栏使得尽可能减少打架的牛的对数。 比如下图中,相同的字符表示会相互打架的牛,我们可以建3条栅栏(红线),使得所有敌对关系的牛都隔离开。

输入

第一行是一个整数T(1≤T≤400),表示样例的个数。 每个样例的第一行是4个整数n(1≤n≤100),m(1≤m≤100),p(1≤p≤2nm−n−m),k(1≤k≤max(1,n+m−2))。 以后的p行,每行4个整数x1,y1,x2,y2(1≤x1,x2≤m;1≤y1,y2≤n),表示(x1,y1)与(x2,y2)的牛需要分开。输入保证没有重复信息并且输入的都是相邻格。

输出

每行输出一个样例的结果,输出在建立k条栅栏的情况下,还会打架的牛的对数。如果可以完全分隔开牛,那么还需要输出需要建立的最少的栅栏数。

样例输入

2
5 5 3 4
1 2 2 2
2 3 3 3
2 4 2 5

5 5 3 1
1 2 2 2
2 3 3 3
2 4 2 5

样例输出

0 3
2

样例解释

输入的样例即图示,明显第一个样例中只需要3条栅栏就能把所有敌对的牛分开;第二个样例只能分开1对牛,所以还剩2对敌对关系的牛。

提示

巨大的输入量,请使用C风格的输入。

解题思路:

  • 有 n*m 个格子,所以有 n-1 个行栅栏,有 m-1 个列栅栏,每有一对敌对牛在某一栅栏两侧,即在该处栅栏,记录   敌对牛数量 ++ .
  • 把各行、列 记录的数量规整到一个数组中, 得到总共需要建造的栅栏数目。
  • 如果数量小于等于 k,直接输出; 如果数量大于k,再额外处理,计算最少剩余敌对牛数量。

AC代码:

#include <stdio.h>
#include <stdlib.h>

int cmp(const void* p1, const void* p2){        // 降序排列
    return *(int *)p2 - *(int *)p1;
}
int Min(int x,int y){
    return x>y ? y : x;
}
int Max(int x,int y){
    return x<y ? y : x;
}

int main()
{
    int T,n,m,p,k,x1,x2,y1,y2;
    scanf("%d",&T);
    while (T --)
    {
        scanf("%d %d %d %d",&n,&m,&p,&k);
        int fence[3][102] = {0};             // 第一维 0 代表行栅栏, 1 代表列栅栏
        int fence_num[204] = {0};            // 存储各行各列分别有多少头 敌对牛
        for (int i = 1; i <= p; i ++)
        {
            scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
            if (x1 != x2)  fence[0][Min(x1,x2)] ++;     // 如果两牛上下敌对, fence[0][较小的坐标] ++
            if (y1 != y2)  fence[1][Min(y1,y2)] ++;     // 如果两牛左右敌对, 列栅栏分隔 敌对牛数量 ++
        }
        int num = 0, ans = 0, maxt = Max(n,m);
        for (int i = 1; i <= maxt; i ++)
        {
            if (fence[0][i] != 0)  fence_num[num++] = fence[0][i];  // 如果该行有敌对牛, 记录下敌对牛数量
            if (fence[1][i] != 0)  fence_num[num++] = fence[1][i];
        }   // 有 num 行/列 的牛需要隔离, 即需要 num 个栅栏

        if (num <= k)    printf("0 %d\n",num);
        else
        {
            qsort(fence_num,num,sizeof(int),cmp);   // 排序,优先在 敌对牛数量多的地方 建造栅栏
            for (int i = k; i < num; i ++)          // 栅栏数量不够, 还剩下 ans 个敌对牛未隔离
                ans += fence_num[i];
            printf("%d\n",ans);
        }
    }
    return 0;
}

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值