题目大意:
平面直角坐标系上有
个整点
,每个点向上下左右四个方向之一连出一条射线,这些射线不能相交且射线不能经过除了发出点之外的其他点。
有多少种方法选择每个点的方向,使得没有冲突,输出方案数对
取模后的值。
分析:
一个点的某个方向上有另一点,则这个方向一定无法选择
然后我们考虑
,
将
个点以
为第一关键字升序排列,
相同时将
升序排列
然后令
表示前
个点中选出点的组合使得满足
①发出射线方向向右的点的纵坐标
最大的点为点
,反之,
最小的点为
②发出射线方向向上的点的纵坐标
最小的点为点
③发出射线方向向下的点的纵坐标
最大的点为点
的方案数的总和。
初值:
然后我们考虑对于第
个点,
然后枚举射线方向,如果这个方向能够畅通(无其他点阻碍),则
我们枚举
,当
不为
(有方案存在)时,
考虑转移
射线向上, 且
,则它不会与这个组合中的所有线相交,有可能更新
射线向下,且
,则它不会与这个组合中的所有线相交,有可能更新
射线向左,且
,则它不会与这个组合的所有线相交,也没可能比
更优。
射线向右,此时不需要有任何限制,也不会和这个组合的所有线相交,可能更新
。
//
,
是根据其纵坐标比较,返回的是对应点编号。
时间复杂度:
但是因为有各种情况的剪枝跑不满,
然后就过了,注意滚动数组优化第一维内存
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
#include <algorithm>
#define N 55
using namespace std;
const int modn = 998244353;
struct Node { int x, y; }a[N];
int dp[2][N][N][N][N], n, total;
bool cmp(Node aa, Node bb)
{
if (aa.x == bb.x) return aa.y < bb.y;
return aa.x < bb.x;
}
int Minid(int x, int y)
{
if (!x) return y;
if (!y) return x;
if (a[x].y < a[y].y) return x;
return y;
}
int Maxid(int x, int y)
{
if (!y) return x;
if (!x) return y;
if (a[x].y < a[y].y) return y;
return x;
}
bool check(int p, int q, int opt)
{
if (opt == 1 && a[p].x == a[q].x && a[p].y < a[q].y) return 1;
if (opt == 2 && a[p].x == a[q].x && a[p].y > a[q].y) return 1;
if (opt == 3 && a[p].y == a[q].y && a[p].x > a[q].x) return 1;
if (opt == 4 && a[p].y == a[q].y && a[p].x < a[q].x) return 1;
return 0;
}
int main()
{
int n, ans = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d %d", &a[i].x, &a[i].y);
sort(a + 1, a + n + 1, cmp);
dp[0][0][0][0][0] = 1;
for (int C = 1; C <= n; C++)
{
int noww = C % 2;
int past = (C + 1) % 2;
for (int opt = 1; opt <= 4; opt++)
{
bool usepower = 0;
for (int D = 1; D <= n; D++)
{ usepower |= check(C, D, opt); if (usepower) break; }
if (!usepower)
{
for (int i = 0; i < C; i++)
for (int j = 0; j < C; j++)
for (int k = 0; k < C; k++)
for (int l = 0; l < C; l++)
if (dp[past][i][j][k][l])
{
if (opt == 1 && (a[C].y > a[i].y || !i))
dp[noww][i][j][Minid(C, k)][l] = (dp[noww][i][j][Minid(C, k)][l] + dp[past][i][j][k][l]) % modn;
if (opt == 2 && (a[C].y < a[j].y || !j))
dp[noww][i][j][k][Maxid(C, l)] = (dp[noww][i][j][k][Maxid(C, l)] + dp[past][i][j][k][l]) % modn;
if (opt == 3 && ((a[k].y > a[C].y && a[l].y < a[C].y) || (!k && !l) ||
(a[k].y > a[C].y && !l) || (a[l].y < a[C].y && !k)))
dp[noww][i][j][k][l] = (dp[noww][i][j][k][l] + dp[past][i][j][k][l]) % modn;
if (opt == 4)
dp[noww][Maxid(C, i)][Minid(C, j)][k][l] = (dp[noww][Maxid(C, i)][Minid(C, j)][k][l] + dp[past][i][j][k][l]) % modn;
}
}
}
for (int i = 0; i <= C; i++)
for (int j = 0; j <= C; j++)
for (int k = 0; k <= C; k++)
for (int l = 0; l <= C; l++) dp[past][i][j][k][l] = 0;
}
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
for (int k = 0; k <= n; k++)
for (int l = 0; l <= n; l++)
total = (total + dp[n % 2][i][j][k][l]) % modn;
printf("%d\n", total);
}