zzulioj 1963:Deadline

来源:互联网 发布:剑网3官方正太捏脸数据 编辑:程序博客网 时间:2024/06/16 09:17

题目链接:点击查看题目
1963: Deadline

Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 27 Solved: 17

Description

刷了一天题的zy已经筋疲力尽,正在他准备上床时,才意识到自己所有科目的作业都没写,但这个时候再认真写
就已经晚了,于是他只好找同学抄,但其实班里也只有那么寥寥几个人写了作业,这就让zy非常头疼,因为平时分还是
非常重要的。
现已知有m门科目要交作业,班里只有n个人写了作业,问zy至少要找多少人借作业才能把所有作业全部搞定
PS:zy找同学借作业时会将那个同学的所有作业全部借来
Input

单实例测试,
第一行输入两个正整数n,m(n,m<=7)
接下来是一个n*m的01矩阵,第i行第j列为1表示第i个人做了第j门作业,为0表示没做,数据保证每个作业至少有一个人做了
Output

输出一个整数表示zy最少要找多少人

Sample Input

5 7
1 0 0 1 1 1 1
0 1 0 0 1 1 0
0 0 1 1 0 0 1
0 1 1 0 0 0 1
1 0 1 0 1 1 1
Sample Output

2
HINT

对于样例,zy只要找第1个同学和第4个同学即可!

基本思路

面对每一位同学的作业,zy都可以借或者不借。借的话把当前同学写的作业拿到自己手里, 然后去找下一位同学。不想借的话就跳过直接去 找下一位同学。

下附代码:

下面是三种代码, 其实方法是一样的,穷举每一种可能, 但是在实现过程还是有差异的。
1,

#include <stdio.h>#include <stdlib.h>#include <string.h>int a[10][10], c[10];int n, m, ans;void dfs(int num, int x);//num为当前还需借几位同学的作业int main ()             //x为当前面对同学的编号{    scanf("%d%d", &n, &m);    int i,j;    for (i = 0 ; i < n ; i ++)        for (j = 0 ; j < m ; j ++)            scanf("%d", &a[i][j]);    for (i = 1 ; i <= n ; i ++)//枚举可能借i位同学的作业    {        ans = 0;        memset(c, 0, sizeof(c));        dfs(i, 0);        if (ans)        {            printf("%d\n", i);            break;        }    }    return 0;}void dfs(int num, int x){    if (ans == 1) return;    if (num == 0)    {        int i;        for (i = 0 ; i < m ; i ++)            if (c[i] == 0) return;        ans = 1; return;    }    if(x >= n) return ;    dfs(num, x+1); //不借当前同学的作业    int i;    for(i = 0; i < m ; i ++) //借当前同学的作业      c[i] += a[x][i];    dfs(num-1, x+1); //借的话num-1,再考虑下一位同学    for(i = 0; i < m ; i ++) //复原      c[i] -= a[x][i];}

2,

#include <stdio.h>#include <stdlib.h>int a[10][10], ans, vis[10], n, m;//vis代表m门作业void dfs(int num, int k, int cnt)//num代表借了几个同学的作业//当前正考虑要不要借第k个同学的作业,已借了cnt门作业{    int i;    if(k == n)//借到第k个同学时, 判断是否借齐门作业    {        if(cnt == m)        ans = ans > num ? num : ans;//更新借最少同学的作业        return;    }    dfs(num, k+1, cnt);//不借k同学的作业, 考虑下一位    int c = 0;    for(i = 0 ; i < m ; i ++)//借k同学的作业      {          if(a[k][i])//如果k同学写了当前还没借到的那门作业,加上这门          {              if(vis[i] == 0)                c ++;              vis[i] ++;          }      }    dfs(num+1, k+1, cnt+c);//借k同学的作业, 考虑下一位    for(i = 0 ; i < m ; i ++)//vis复原        if(a[k][i] && vis[i])        vis[i] --;}int main(){    int i, j;    scanf("%d %d", &n, &m);    for(i = 0;i < n;i++)        for(j = 0 ; j < m ; j ++)        scanf("%d", &a[i][j]);    ans = 10;//用来记录当前最少借几名同学可以借全m门作业,所以初始定一个较大的数    dfs(0, 0, 0);    printf("%d\n", ans);    return 0;}

3,

#include <stdio.h>#include <stdlib.h>#include <string.h>int a[10][10],sta[9]={1, 2, 4, 8, 16, 32, 64, 128, 256}, work[10], min=10;int main(){    int i, j ;    int n, m;    scanf("%d%d", &n, &m);    for (i = 0 ; i < n ; i ++)        for (j = 0 ; j < m ; j ++)            scanf("%d", &a[i][j]);    for (i = 0 ; i < sta[n] ; i ++)//一共0~sta[n]-1种情况, 每个数都代表一种情况    {                             //比如第8种情况对应数字7,其二进制为000111,                                 //表示借第1,2,3位同学的作业        memset(work, 0, sizeof(work));        int step = i, ans = 0;        for (j = 0 ; j < n ; j ++)//各个同学的状态若为1,则借这位同学的作业        {            if (step % 2 == 1)            {                int k;                for (k = 0 ; k < m ; k ++)                    work[k] += a[j][k];                ans +;            }            step /= 2;        }        for (j = 0 ; j < m ; j ++)            if (work[j] == 0)                break;        if (j == m && ans < min)//若m门作业借齐了, 则更新最小值            min = ans;    }    printf("%d\n", min);    return 0;}
1 0
原创粉丝点击