usaco1.3.5(dfs生成配对情况)

来源:互联网 发布:护眼手机膜 知乎 编辑:程序博客网 时间:2024/06/06 01:49
/*ID:lvfuan11PROG:wormholeLANG:C++translation:在二维平面上有多个虫洞,现在要两两配对连起来,使得在某一位置出发沿着++x方向能够陷入死循环。问有几种连接方式?solution:给虫洞编号。利用dfs递归生成所有可能的配对情况。每次递归时,选择未配对的最小编号的点,与剩下的点一一测试,如果这种方案可行,就将计数器ans++。否则便返回。note:1:一开始的递归生成方式是枚举剩下的两个点来配对看是否能够符合要求。但是注意这样递归枚举在每层递归当中可能重复枚举。因为在i层枚举的a和b可能在i+k层已经枚举了。所以保证不重复枚举的方法就是固定一个点,然后枚举另外一个点,即可保证不重复枚举。2:这道题可以总结出来枚举类似配对情况的方法。(仅仅限于数据量小的情况)date:2016.9.30*/#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int n, ans;struct Point {int x, y;Point(int x_, int y_) : x(x_), y(y_) {}Point() {}bool operator < (const Point& rhs) const {if(x == rhs.x)return y < rhs.y;elsereturn x < rhs.x;}} p[15];int partner[15];int G[15][15], vis[15];int nextRight[15];bool check() {//模拟bessie的走法,只要进入一个曾经进入过的点就说明陷入了循环当中for(int s = 1; s <= n; s++) {//枚举起点int pos = s;for(int cnt = 0; cnt < n; cnt++) {pos = nextRight[partner[pos]];}if(pos != 0)return true;}return false;}void dfs(int d) {if(d == n) {if(check())ans++;return;}for(int i = 1; i <= n; i++) if(partner[i] == -1) {for(int j = i + 1; j <= n; j++) if(partner[j] == -1) {partner[i] = j;partner[j] = i;dfs(d + 2);partner[i] = partner[j] = -1;}break;}}int main(){freopen("wormhole.in", "r", stdin);freopen("wormhole.out", "w", stdout);    scanf("%d", &n);    for(int i = 1; i <= n; i++)scanf("%d%d", &p[i].x, &p[i].y);    sort(p, p + n);    memset(nextRight, 0, sizeof(nextRight));    for(int i = 1; i <= n; i++) {for(int j = 1; j <= n; j++) {if(p[i].y == p[j].y && p[j].x > p[i].x) {if(nextRight[i] == 0 || p[nextRight[i]].x - p[i].x > p[j].x - p[i].x)nextRight[i] = j;}}    }    memset(partner, -1, sizeof(partner));    memset(G, 0, sizeof(G));    ans = 0;dfs(0);    printf("%d\n", ans);    return 0;}

0 0