AcWing 323 . 战略游戏


题目传送门

这是基础课原题

#include 

using namespace std;

const int N = 1510;         //因为题目明确是有向图,无需M=N*2
int h[N], e[N], ne[N], idx; //邻接表
int f[N][2];
/**
 集合:    以结点i为 根节点 的子树,在 i 上放置哨兵(1) 和不放哨兵(0) 的方案
 状态表示: 方案中,放置的哨兵数量 最少
 状态计算:
 */
bool st[N];                 //用于判断是不是根节点

//邻接表模板
void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void dfs(int u) {
    //状态初始化
    f[u][0] = 0, f[u][1] = 1;
    //遍历每一条出边
    for (int i = h[u]; ~i; i = ne[i]) {
        int j = e[i];
        dfs(j);
        //状态转移方程
        f[u][0] += f[j][1];//节点u不放置哨兵,那么一定要从某一邻接节点放置哨兵
        f[u][1] += min(f[j][0], f[j][1]);//如果节点u放置了哨兵,那么邻接节点可以选择放置或者不放置
    }
}

int main() {
    //n组数据
    int n;
    //不断读入数据
    while (cin >> n) {
        //多组数据,清空邻接表
        memset(h, -1, sizeof h), idx = 0;
        //清空状态数组
        memset(st, 0, sizeof st);
        //n个节点
        for (int i = 1; i <= n; i++) {
            int x, m;
            scanf("%d:(%d)", &x, &m);//scanf可以按格式读入数据
            while (m--) {
                int y;
                cin >> y;
                //添加一条x->y的有向边
                //数据样例:1出发可以到达2,3;说明是有向图
                add(x, y);
                //标识y不是根
                st[y] = true;
            }
        }
        //有向图,需要找到出根
        int root = 0;
        while (st[root]) root++;

        //从根开始
        dfs(root);

        //输出 两个结果取个 min
        printf("%d\n", min(f[root][0], f[root][1]));
    }
    return 0;
}


相关