UVa 225 Golygons (黄金图型)——我有与众不同的剪枝

Imagine a country whose cities have all their streets laid out in a regular grid. Now suppose that atourist with an obsession for geometry is planning expeditions to several such cities.

Starting each expedition from the central cross-roads of a city, the intersection labelled (0,0), ourmathematical visitor wants to set off north, south, east or west, travel one block, and view the sightsat the intersection (0,1) after going north, (0,-1) after going south, (1,0) after going east or (-1,0) aftergoing west. Feeling ever more enthused by the regularity of the city, our mathematician would like towalk a longer segment before stopping next, going two blocks.

What’s more, our visitor doesn’t want to carry on in the same direction as before, nor wishes todouble back, so will make a 90oturn either left or right. The next segment should be three blocks,again followed by a right-angle turn, then four, five, and so on with ever-increasing lengths until finally,at the end of the day, our weary traveller returns to the starting point, (0,0).

The possibly self-intersecting figure described by these geometrical travels is called a golygon

Unfortunately, our traveller will making these visits in the height of summer when road workswill disrupt the stark regularity of the cities’ grids. At some intersections there will be impassableobstructions. Luckily, however, the country’s limited budget means there will never be more than 50road works blocking the streets of any particular city. In an attempt to gain accountability to itscitizens, the city publishes the plans of road works in advance. Our mathematician has obtained a copyof these plans and will ensure that no golygonal trips get mired in molten tar.

Write a program that constructs all possible golygons for a city.

Input:

Since our tourist wants to visit several cities, the input file will begin with a line containing an integerspecifying the number of cities to be visited.

For each city there will follow a line containing a positive integer not greater than 20 indicating thelength of the longest edge of the golygon. That will be the length of the last edge which returns thetraveler to (0,0). Following this on a new line will be an integer from 0 to 50 inclusive which indicateshow many intersections are blocked. Then there will be this many pairs of integers, one pair per line,each pair indicating the x and y coordinates of one blockage.

Output:
For each city in the input, construct all possible golygons. Each golygon must be represented by asequence of characters from the set {n,s,e,w} on a line of its own. Following the list of golygonsshould be a line indicating how many solutions were found. This line should be formatted as shown inthe example output. A blank line should appear following the output for each city.

Note: See on the right the diagram of the 1st City

Sample Input

2

8

2

-2 0

6 -2

8

2

2 1

-2 0

Sample Output

wsenenws

Found 1 golygon(s).


Found 0 golygon(s).



        一道命题很酷的DFS题目,这一次作者走路的方式和平时有些不一样,他一定要每次不走相同的方向与之前一次不同,而且很有强迫症的是每次都要比之前一次多走一步,由于他奇怪的癖好这个问题让我有了些灵感,由于他每次拐弯的都是九十度角的,所以他走的路径一定是一个有多个长方形组成的图案,这样子这个问题就可以简化成,给我们长度为1,2,3,4.....n的n的条线段,要我们在两个长度相邻的线段不在同一边的情况下将其组成矩形。怎么样这是不是和我们小学的奥数题很小,由于n<=20,我们可以手动推倒,不难发现只有n的累加和可以被4整除的情况下才可组成矩形,这样子有可能让作者走回原点的n只有四个即7.8.15.16.

       所以我们只有在输入的数字是这四个的时候才需要计算。

下面的是AC代码,但是没有做过多的优化,可以发现上述的方法可以提高很高的效率。

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int temp=105;
const int N=250;
const int dir[4][2]={{1,0},{0,1},{0,-1},{-1,0}};

int n,m,num=0;
int a[25],pd[N][N];
char c[5]={ 'e','n','s','w' };

bool judge(int x,int y,int d,int k)
{
    for(int i=1;i<=k;i++){
        x+=dir[d][0];
        y+=dir[d][1];
        if(abs(x)>temp||abs(y)>temp)continue;
        if(pd[x+temp][y+temp]==-1)return true;
    }
    return false;
}

void dfs(int x,int y,int d,int f)
{
    if(d>n){                                               //判断,输出
        if(x==0&&y==0){
            for(int i=1;i<=n;i++)printf("%c",c[a[i]]);
            printf("\n");
            num++;
        }
        return;
    }

    int& i=a[d];                                          //回溯模块,这里的写法借鉴了博客大神JeraKrs,看他的博客感觉学到了很多
    for(i=0;i<4;i++) 
    {                                                     //不过他用的剪枝方法不是我发现的这种投机取巧的方法
        if(i==f||i+f==3)continue;                         //用于判断方向和上一次不一样
        if(judge(x,y,i,d))continue; 
        int p=x+dir[i][0]*d,q=y+dir[i][1]*d;              //在坐标上的表示要加上temp,来表示负数,而d来表示走了多少步数,真的很厉害
        if(pd[p+temp][q+temp])continue;
        pd[p+temp][q+temp]=1;
        dfs(p,q,d+1,i);
        pd[p+temp][q+temp]=0;
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int k;
        memset(pd,0,sizeof(pd));
        memset(a,0,sizeof(a));
        scanf("%d",&n);
        scanf("%d",&k);
        while(k--)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            if(abs(a)>temp||abs(b)>temp)continue;
            pd[a+temp][b+temp]=-1;
        }
        if(n==7||n==8||n==15||n==16)                      //在这里进行减枝
        {
            
            for(int i=2;i<=n;i++)m+=n;
            
            num=0;
            dfs(0,0,1,-1);
            printf("Found %d golygon(s).\n",num);
        }
        else printf("Found 0 golygon(s).\n");
        cout<<endl;

    }
    return 0;

}



猜你喜欢

转载自blog.csdn.net/j1nab1n9/article/details/76500244
今日推荐