POJ 2790 Consecutive ones (搜索 + 剪枝)

40 篇文章 1 订阅
12 篇文章 0 订阅

大体题意:

给你一个n*m的0-1矩阵(n,m <= 400),它的第一列固定不动,其他列你可以随意交换。你要使每行的1都连续地出现。求出这样的方案。保证答案唯一!

思路:

因为保证了答案唯一,所有正解只有一个,因此不合法的情况会有很多,因此我们可以考虑 搜索 + 剪枝的方案。

矩阵只有0 和1 因此一个位置要么填0要么填1,这两种方式都考虑到剪枝就可以很轻松的过了!

最先想到的肯定是枚举列,在枚举每一行检测是否合法!

剪枝方法:

如果这一列这一个位置是1的话,那么前面的一个位置也必须是1,否则就不连续了!

如果这一列这一个位置是0的话  并且  前面出现了1,那么后面肯定不能有1了,否则就被0隔开了! 因此可以检测前面1的个数是否等于这一行所有1的个数。

这两种剪枝,后一种比较厉害。

两种都考虑就好了!63ms就可以过了

详细见代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 400 + 7;
char s[maxn][maxn];
int a[maxn][maxn];
int ans[maxn];
int vis[maxn], one[maxn], sum[maxn];
int n, m;
int all = 0;
void dfs(int c){
    if (all)return;
    if (c == m){
        all = 1;
        return;
    }
    for (int i = 1; i < m; ++i){
        if (vis[i] == 0){
            bool ok = 1;
            for (int j = 0; j < n; ++j){
                if (a[j][i] == 1){
                    if (one[j] && a[j][ans[c-1]] == 0){
                        ok = 0;
                        break;
                    }
                }else {
                    if (one[j] && one[j] < sum[j]){
                        ok= 0;
                        break;
                    }
                }
            }
            if (!ok)continue;
            vis[i] = 1;
            for (int j = 0; j < n; ++j){
                one[j] += a[j][i];
            }
            if (!all)ans[c] = i;
            dfs(c+1);
            vis[i] = 0;
            for (int j = 0; j < n; ++j){
                one[j] -= a[j][i];
            }
        }
    }
}
int main(){
    scanf("%d %d",&n, &m);
    memset(vis,0,sizeof vis);
    vis[0] = 1;
    for (int i = 0; i < n; ++i){
        scanf("%s",s[i]);
        if (s[i][0] == '1')one[i]++;
        for (int j = 0; s[i][j]; ++j){
            if (s[i][j] == '1')a[i][j] = 1;
            else a[i][j] = 0;
            sum[i] += a[i][j];
        }
    }
    dfs(1);
    for (int i = 0; i < m; ++i) printf("%d\n",ans[i]);
    return 0;
}


Consecutive ones
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 605 Accepted: 384

Description

00000000000000000011 
11111111000000000000 
00000000000000001111 
00000000000011000000 
00000000000000111100 
00000000000001110000 
00111000000000000000 
00000000000111000000 
00000000111100000000 
00000000000000000001 
11000000000000000000 
00001111111000000000 
00000111111111111111 
00000000011111100000 
00000000001111111110 
00000000000000011110 
00000001111100000000 
00000011111111110000 
00011110000000000000 
01111111111100000000 
00000000000000000111

A time schedule is represented by a 0-1 matrix with n lines and m columns. Each line represents a person and each column an event. All the persons participating to an event have a one in the corresponding entry of their line. Persons not attending the event have a zero entry in that column. Events occur consecutively. 
Problem 
Problem Write a program that finds a smart permutation of the events where each person attends all its events in a row. In other words, permute the columns of the matrix so that all ones are consecutive in each line. 

Input

The first line of the input consists in the number n<=400 of lines. The second line contains m<=400 , the number of columns. Then comes the n lines of the matrix. Each line consists in m characters `0' or `1'. 

The input matrix is chosen so that there exists only one smart permutation which preserves column 0 in position 0. To make things easier, any two columns share few common one entries.

Output

The output consists of m numbers indicating the smart permutation of the columns. The first number must be 0 as column 0 does not move. The second number indicate the index (in the input matrix) of the second column, and so on.

Sample Input

3
4
0110
0001
1101

Sample Output

0
3
1
2

Hint

Sample input2 


01010 
01000 
10101 
10100 
00011 
00101 
Sample output2 





Sample input3 
21 
20 
00101000000000000000 
10010010010110010100 
00101101000000000000 
01000000000000001000 
00000101100000100000 
01000000100000100000 
00000010000110000000 
01000000000001001000 
00000000001001000011 
00001000000000000000 
10000000000000000100 
00010010011000010011 
01111101111001111011 
01000000000001101011 
01100101100001101001 
00100101100000000000 
00010000001001000011 
01010000101001111011 
00000010010010010000 
00010010011111010111 
00101001000000000000 
Sample output3 

17 
11 
12 


15 

10 
18 
19 
13 
16 

14 




4

Source

[Submit]   [Go Back]   [Status]   [Discuss]




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值