B - Colored Blankets Gym - 100513B(构造)

Recently Polycarp has opened a blankets store and he faced with many challenges.

He has got k blankets. A blanket has two sides, each of k blankets has at most one colored side. So either both sides are uncolored or one side is colored and the other one is not. If a side is colored, one of n possible colors is used. It is known that k is divisible by n.

Polycarp wants to color all uncolored sides in such a way that:

each blanket will have both sides colored (one color per side), the colors can be the same or different, all the used colors are from n possible colors;
it will be possible to compose n kits with blankets in each kit that blankets in each kit are identically colored.
It is allowed to turn over blankets to determine that they are identically colored: for example, red-blue and blue-red blankets are identically colored. Blankets in different kits can be identically colored.

Input
The first line contains two integer numbers k and n (1 ≤ n ≤ k ≤ 1000) — number of blankets and colors. It is guaranteed that k is divisible by n. The second line contains a sequence of integers c 1, c 2, …, c k (1 ≤ c i ≤ n or c i =  - 1), where c i stands for the color of the colored side of the i-th blanket or  - 1 if it is uncolored.

Output
If there is no solution for the problem, print “No” in the first line. Otherwise print a line containing “Yes” and k lines describing each blanket. The i-th line should contain a pair of colors (integers in the range 1, 2, …, n) used for the i-th blanket. You may print colors in pairs in any order.

If there are multiple solutions, print any of them.

Examples
Input
6 2
1 1 2 2 -1 2
Output
Yes
1 2
2 1
2 2
2 2
2 1
2 2
Input
8 4
4 -1 1 -1 4 3 -1 -1
Output
Yes
4 1
2 1
2 1
3 1
1 4
3 1
4 1
4 1

题意:
n个卡片,k种颜色,有些卡片有一面有颜色,有些卡片两面都没有颜色。要求你进行涂色,使得将这些卡片分成k组,每组内卡片都相同(意味着卡面两面颜色相同)。

思路:
将所有为-1的卡牌正面涂上颜色k,
同时按照颜色分成k组并进行排序,
那么对于当前数目最小那一组,

  1. 如果数目大于等于n/k,那么把 n/k 数目的卡牌正反面涂上自己颜色,并去掉。
  2. 如果数目小于n/k,那么找到最大的一组,补全最小那一组使得其数目大于n/k,并去掉最小这一组。

对于第二步,假设x = n/k,那么当前有k个颜色,总数为x * k,根据鸽巢定理,最大颜色数目至少为x。此时一定满足。
第一轮会消耗掉x个卡牌,并且会消耗掉一个颜色。剩余 x ( k 1 ) x*(k-1) 个卡牌,剩余 k 1 k-1 个颜色,同理最大数目至少为x,之后也一定能满足。所以保证一定有解。

AC代码,实现上看了学长的代码,也就是通过vector记录每个颜色对应的卡牌下标。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <queue>

using namespace std;

const int maxn = 10005;

int b[maxn],c[maxn],d[maxn];

vector<int>a[maxn];

int cmp(int x,int y) {
    return a[x].size() < a[y].size();
}

int main() {
    int n,k;scanf("%d%d",&n,&k);
    for(int i = 1;i <= n;i++) {
        scanf("%d",&c[i]);
        if(c[i] == -1) c[i] = k;
        a[c[i]].push_back(i);
    }
    int k1 = k,k2 = n / k;
    
    for(int i = 1;i <= n;i++) {
        for(int j = 1;j <= k1;j++) {
            d[j] = j;
        }
        sort(d + 1,d + 1 + k1,cmp);
        
        int first = -1;
        for(int j = 1;j <= k1;j++) {
            if(a[d[j]].size() == 0) continue;
            first = d[j];
            break;
        }
        
        if(first == -1) break;
        
        if(a[first].size() > k2) {
            for(int j = 1;j <= k2;j++) {
                b[a[first].back()] = first;
                a[first].pop_back();
            }
            
        }
        else {
            int num = k2 - a[first].size();
            for(int j = 1;j <= num;j++) {
                b[a[d[k1]].back()] = first;
                a[d[k1]].pop_back();
            }
            for(int j = 0;j < a[first].size();j++) {
                b[a[first][j]] = d[k1];
            }
            a[first].clear();
        }
    }
    
    printf("Yes\n");
    for(int i = 1;i <= n;i++) {
        printf("%d %d\n",c[i],b[i]);
    }
    return 0;
}

WA65的代码,使用map输出(感觉可以啊),并且没有严格使用最大值。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
 
using namespace std;
 
const int maxn = 1005;
 
int c[maxn];
map<pair<int,int>,int> b;
 
struct Node {
    int id,v;
}a[maxn];
 
int cmp(Node a,Node b) {
    return a.v < b.v;
}
 
int main() {
    int n,k;scanf("%d%d",&n,&k);
    for(int i = 1;i <= n;i++) {
        scanf("%d",&c[i]);
        if(c[i] == -1) c[i] = k;
        a[c[i]].v++;
        a[c[i]].id = c[i];
    }
    int k1 = k,k2 = n / k;
    for(int i = 1;i <= k1;i++) {
        a[i].id = i;
    }
    sort(a + 1,a + 1 + k1,cmp);
    
    
    for(int i = 1;i <= k1;i++) {
        if(a[i].v == 0) continue;
        if(a[i].v >= k2) {
            b[{a[i].id,a[i].id}] += a[i].v / k2 * k2;
            a[i].v %= k2;
        }
        for(int j = k1;j >= i + 1;j--) {
            if(a[i].v + a[j].v >= k2) {
                int tmp = k2 - a[i].v;
                b[{a[j].id,a[i].id}] += tmp;
                b[{a[i].id,a[j].id}] += a[i].v;
                a[i].v = 0;
                a[j].v -= tmp;
                break;
            }
        }
    }
    
    printf("Yes\n");
    for(int i = 1;i <= n;i++) {
        for(int j = 1;j <= k1;j++) {
            if(b[{c[i],j}]) {
                b[{c[i],j}]--;
                printf("%d %d\n",c[i],j);
                break;
            }
        }
    }
    return 0;
}
 
 
原创文章 930 获赞 38 访问量 5万+

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/106054091
今日推荐