【Algorithm】 着色
来源:互联网 发布:网络传销案 编辑:程序博客网 时间:2024/06/05 09:00
题目:
图由N个点M条边组成,一条边连接2个点, 给图中的点着色,只能是黑色或白色,有一个条件,共享一条边的两个点不能同时为黑色
这里的图是一颗树,不存在环路,无向
思路:
正常思路就是递归,先给一个点着色,然后检查这个点之前的点的颜色是否冲突,不冲突继续着色,直到所有的点都有颜色。然后递归,换一个颜色,继续着色。
int ok(int x){ if (color[parent[x]]==1) { return 0; } return 1;}void dfs(int t){ if (t==0) { Answer++; } else { color[t] = 0; dfs(t - 1); color[t] = 1; if (ok(t)) { color[parent[t]] = 1; if (color[t-1] == -1) { dfs(t - 1); } } color[t] = -1; }}
这个当时是可以解决问题的,但是递归的效率不高,当数据量很大的时候,就无法满足。
这里提供一个新的思路。
通过上图我们可以看出,节点之间种类的关系,可以得出所有叶子节点的着白色次数为1,着黑色次数为1,下一步是计算父亲节点的着色次数。当一个节点所有的孩子的着色次数计算完成后,即可得到该节点的着色次数。那么树的根节点的着色次数,就是我们最终要求的节点个数。
这里我们可以创建这样一个数据结构来解决问题。
Head数组中存放所有节点,而每个节点都有一个链表来存其孩子节点。当我们要计算Head[i]的着色次数,就是将其链表节点所有的着色次数分别求出,然后按照公式相乘,就可以得到数组中节点的着色次数。
我们可以在链表结点中保存数组下标,就可以知道这个孩子是否是其他节点的父亲节点,从而来求解节点的着色次数。
如图中所示,假设head数组中第一个元素是0,有2,3两个孩子,那个2,3,在数组中又是其他节点的父亲,必须算到叶子节点之后,才能算出2,3的着色次数。
#include <stdio.h>#define MAX 100001#define MOD 1000000007int Answer = 0;int N;typedef struct NODE{ int id; NODE* next;}Node;typedef struct HEAD{ NODE* next;}Head;Head data[MAX];long long w[MAX];long long b[MAX];void solve(int index, int pre){ Head p = data[index]; Node* t = p.next; while (t) { int child = t->id; if (child != pre) { solve(child, index); w[index] = w[index] * (w[child] + b[child]) % MOD; b[index] = b[index] * w[child] % MOD; // printf("data[%d]'s w=[%d] b=[%d]\n", index, w[index], b[index]); } t = t->next; }}void addnode(int v1, int v2){ Node* p = new NODE; p->id = v2; p->next = NULL; Node* q = data[v1].next; if (q == NULL) { data[v1].next = p; } else { data[v1].next = p; p->next = q; }}int main(void){ int test_case; int T; freopen("input.txt", "r", stdin); setbuf(stdout, NULL); scanf("%d", &T);// T = 1; for (test_case = 1; test_case <= T; ++test_case) { Answer = 0; scanf("%d",&N); int i ; for (i = 1; i <= N; i++) { w[i] = 1; b[i] = 1; // data[i].next = NULL; Node* t = data[i].next; while (t) { data[i].next = t->next; delete t; t = data[i].next; } data[i].next = NULL; } for ( i = 1; i <= N-1; i++) { int v1, v2; scanf("%d%d",&v1,&v2); addnode(v1,v2); addnode(v2,v1); } // for (int i = 1; i < N; ++i){ // printf("%d\n", data[i].next->id); // } solve(1,-1); Answer = (b[1] + w[1]) % MOD; printf("#%d %lld\n", test_case, Answer); } return 0;}
代码中需要注意的细节很多,比如给head数组的元素添加一个节点时,不用插入到链表最后,而是就近原则,不然性能会很差
还有就是计算着色次数的时候,不能将自己算进去,所以要判断id!=pre, 比如计算2的时候,2作为元素0的node,需要计算,但是作为head的元素2的时候,不能计算。
- 【Algorithm】 着色
- 【Algorithm】 着色
- 着色
- 着色
- Algorithm
- Algorithm
- algorithm
- algorithm
- algorithm
- algorithm
- algorithm
- Algorithm
- Algorithm
- algorithm
- Algorithm
- Algorithm
- algorithm
- algorithm
- 理解Spark的核心RDD
- Vue生命周期详解
- JSP中EL表达式详解
- 函数指针的两种调用方式
- 编译linux内核加入 GPIO support 方法
- 【Algorithm】 着色
- Java反射机制剖析
- Spring详解(四)------注解配置IOC、DI
- 硬件电路设计经验教训浅谈
- 2017.9.6模拟考试
- hello bash
- vuejs路由
- C++里类中的析构函数和拷贝构造函数
- java equals和==的区别