HDU-5031-Lines(DFS)

Problem Description

You play a game with your friend. He draws several lines on the paper with n×m square grids (see the left figure). After that, he writes down the number of lines passing through every integer coordinate in a matrix (see the right figure).

The number of lines passing though coordinate (i,j) is written in cell (i,j) in the right figure.(i,j both start from 0).

You are given the matrix written by your friend. You need to figure out the possible minimal number of lines your friend drew on the paper.

Input

The first line of the input contains an integer T indicating the number of test cases( 0 < T <= 10).

For each test case, the first line contains two integers n, m (1 ≤ n, m ≤ 50) representing the size of the grids on the paper. The following (n+1) × (m+1) numbers is what your friend writes. It is guaranteed that the number of lines your friend draws does not
exceed 14. Each line passes through integer coordinates at least three times.

Output

For each test case, you need to output the minimal number of lines your friend drew on the paper in a single line.

Sample Input

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

Sample Output

4

Source

2014 ACM/ICPC Asia Regional Guangzhou Online

思路:枚举经过当前点的所有可能直线即可。详见代码。

#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;

int mp[55][55],ans,n,m,sum;

map<double,bool>db;//用来根据斜率判重

void dfs(int dep,int remain)
{
    if(dep>=ans) return;

    if(!remain)
    {
        ans=min(ans,dep);

        return;
    }

    int i,j,p,q,cnt;
    bool flag=0;

    for(i=0;i<n && !flag;i++)
    {
        for(j=0;j<m && !flag;j++)
        {
            if(mp[i][j])
            {
                flag=1;//找到一个点即可,我们要枚举的是经过它的可行直线

                if(i==0)//经过改点的竖直直线
                {
                    for(p=i;p<n;p++) if(!mp[p][j]) break;

                    if(p==n)
                    {
                        for(p=i;p<n;p++) mp[p][j]--;

                        dfs(dep+1,remain-n);

                        for(p=i;p<n;p++) mp[p][j]++;
                    }
                }

                if(j==0)//经过改点的水平直线
                {
                    for(p=j;p<m;p++) if(!mp[i][p]) break;

                    if(p==m)
                    {
                        for(p=j;p<m;p++) mp[i][p]--;

                        dfs(dep+1,remain-m);

                        for(p=j;p<m;p++) mp[i][p]++;
                    }

                }

                db.clear();//清空状态

                for(p=i+1;p<n;p++)
                {
                    for(q=0;q<m;q++)
                    {
                        if(mp[p][q] && p!=i && q!=j)
                        {
                            int x=p-i,y=q-j;

                            if(!db[double(y)/x]) db[double(y)/x]=1;//该斜率直线是否已经找过
                            else continue;

                            cnt=1;

                            while(i+cnt*x>=0 && i+cnt*x<n && j+cnt*y>=0 && j+cnt*y<m && mp[i+cnt*x][j+cnt*y]) cnt++;

                            if(i+cnt*x>=0 && i+cnt*x<n && j+cnt*y>=0 && j+cnt*y<m) continue;//如果后面的不能连续
                            if(i-x>=0 && i-x<n && j-y>=0 && j-y<m) continue;//如果前面的不能连续
                            if(cnt<3) continue;//经过的点少于3个

                            cnt=1;

                            while(i+cnt*x>=0 && i+cnt*x<n && j+cnt*y>=0 && j+cnt*y<m)
                            {
                                mp[i+cnt*x][j+cnt*y]--;

                                cnt++;
                            }

                            mp[i][j]--;

                            dfs(dep+1,remain-cnt);

                            mp[i][j]++;

                            cnt=1;

                            while(i+cnt*x>=0 && i+cnt*x<n && j+cnt*y>=0 && j+cnt*y<m)
                            {
                                mp[i+cnt*x][j+cnt*y]++;

                                cnt++;
                            }
                        }
                    }
                }
            }
        }
    }
}

int main()
{
    int T,i,j;

    scanf("%d",&T);

    while(T--)
    {
        scanf("%d%d",&n,&m);

        n++;
        m++;

        sum=0;

        for(i=0;i<n;i++)
        {
            for(j=0;j<m;j++)
            {
                scanf("%d",&mp[i][j]);

                sum+=mp[i][j];
            }
        }

        ans=min(14,sum/3);

        dfs(0,sum);

        printf("%d\n",ans);
    }
}
时间: 2024-10-29 19:13:43

HDU-5031-Lines(DFS)的相关文章

hdu 5031 Lines 爆搜

其实嘞,这个线可以只延伸一端 然后嘞,爆搜一次就可以 最后嘞,600-800ms过 本弱就是弱啊,你来打我呀-- #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; int a[100][100]; int n,m,ans; bool dfs(int step) { int i,j,t,ii,jj,x,y,cnt,tx,t

HDU 4921 Map DFS+状态压缩+乘法计数

算最多十条链,能截取某前缀段,每种方案都可以算出一个权值,每种方案的概率都是总数分之一,问最后能构成的所有可能方案数. 对计数原理不太敏感,知道是DFS先把链求出来,但是想怎么统计方案的时候想了好久,其实因为只能取某个链的前缀,所以直接取链长加+1 然后相乘即可,当然因为会出现都是空的那种情况,要去掉,全部乘完之后,要-1 然后就是算权值了,权值等于当前加进来的点的总和 以及 等级相同的点的加成,并不是特别好算,这时候考虑每个状态下的点对全局的贡献,对,就是这个思想,用状态压缩来表示状态,然后这

hdu 1501 Zipper dfs

题目链接: HDU - 1501 Given three strings, you are to determine whether the third string can be formed by combining the characters in the first two strings. The first two strings can be mixed arbitrarily, but each must stay in its original order.For examp

hdu 1044(bfs+dfs+剪枝)

Collect More Jewels Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6739    Accepted Submission(s): 1564 Problem Description It is written in the Book of The Lady: After the Creation, the cruel

HDU 1175 连连看(DFS)

Problem Description “连连看”相信很多人都玩过.没玩过也没关系,下面我给大家介绍一下游戏规则:在一个棋盘中,放了很多的棋子.如果某两个相同的棋子,可以通过一条线连起来(这条线不能经过其它棋子),而且线的转折次数不超过两次,那么这两个棋子就可以在棋盘上消去.不好意思,由于我以前没有玩过连连看,咨询了同学的意见,连线不能从外面绕过去的,但事实上这是错的.现在已经酿成大祸,就只能将错就错了,连线不能从外围绕过.玩家鼠标先后点击两块棋子,试图将他们消去,然后游戏的后台判断这两个方格能

HDOJ 5031 Lines

枚举角度DFS.... Lines Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 479    Accepted Submission(s): 140 Problem Description You play a game with your friend. He draws several lines on the paper wi

HDU - 1175 连连看 DFS (记录方向)

连连看HDU - 1175 "连连看"相信很多人都玩过.没玩过也没关系,下面我给大家介绍一下游戏规则:在一个棋盘中,放了很多的棋子.如果某两个相同的棋子,可以通过一条线连起来(这条线不能经过其它棋子),而且线的转折次数不超过两次,那么这两个棋子就可以在棋盘上消去.不好意思,由于我以前没有玩过连连看,咨询了同学的意见,连线不能从外面绕过去的,但事实上这是错的.现在已经酿成大祸,就只能将错就错了,连线不能从外围绕过. 玩家鼠标先后点击两块棋子,试图将他们消去,然后游戏的后台判断这两个方格能

hdu 5438 Ponds dfs

Time Limit: 1500/1000 MS (Java/Others)     Memory Limit: 131072/131072 K (Java/Others) Problem Description Betty owns a lot of ponds, some of them are connected with other ponds by pipes, and there will not be more than one pipe between two ponds. Ea

hdu 1455 Sticks——dfs经典的题目

http://acm.hdu.edu.cn/showproblem.php?pid=1455 题意:几根长度的棍子被分成了很多半.问合成多个长度相同的棍子,棍子长度最小是多少. 题解:很明显是dfs.所以我们首先需要找到,这些棍子可能是多长,肯定是最长的棍子的长度到所有棍子长度和之间的某个长度.找到这些可能之后就直接按照这个长度开始搜.想法是搜到和为这个长度之后记录,然后重新再搜,一直到所有棍子都分配自后就完成了. 重要的剪枝:确定每次搜索的起始位置,这个一定是确定的!!!其次就是相同长度的棍子

hdu 1015(DFS)

Safecracker Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 13237    Accepted Submission(s): 6897 Problem Description === Op tech briefing, 2002/11/02 06:42 CST === "The item is locked in a Klei