A - Kidnapping
题意:n个点,给出这n个点的邻接矩阵,元素大小为对应边的长度,然后给出k个长度,问从结点1开始,依次走完这k个长度后最终到达的结点有哪几个 (2 <= n <= 200, 1 <= k <= 200, 0 <= 矩阵元素 <= 200, 1 <= k个长度中每个长度 <= 200)。
题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=518
——>>看n、k为200,不大,于是直接模拟一次,结果TLE去了。。。
接着想到了dp,设d[i]为依次走完前i个长度时能到达的点的集合(用set),则
状态转换方程为:d[i].insert(v[e]);(v[e]为d[i-1]中的元素经过第i个长度后能到达的点)。
1 #include <cstdio> 2 #include <vector> 3 #include <set> 4 5 using namespace std; 6 7 const int maxn = 200 + 10; 8 int head[maxn], nxt[maxn*maxn], u[maxn*maxn], v[maxn*maxn], w[maxn*maxn], r[maxn]; 9 int n, k, ecnt; 10 set<int> d[maxn]; 11 12 void init(){ 13 int i; 14 for(i = 1; i <= n; i++) head[i] = -1; 15 for(i = 1; i <= k; i++) d[i].clear(); 16 ecnt = 0; 17 } 18 19 void addEdge(int uu, int vv, int ww){ 20 u[ecnt] = uu; 21 v[ecnt] = vv; 22 w[ecnt] = ww; 23 nxt[ecnt] = head[uu]; 24 head[uu] = ecnt; 25 ecnt++; 26 } 27 28 void read(){ 29 int i, j, len; 30 for(i = 1; i <= n; i++) 31 for(j = 1; j <= n; j++){ 32 scanf("%d", &len); 33 if(len) addEdge(i, j, len); 34 } 35 scanf("%d", &k); 36 for(i = 1; i <= k; i++) scanf("%d", &r[i]); 37 } 38 39 void solve(){ 40 int i, e, u; 41 set<int>::iterator p; 42 for(e = head[1]; e != -1; e = nxt[e]){ //第一次后可到达哪 43 if(w[e] == r[1]) d[1].insert(v[e]); 44 } 45 for(i = 2; i <= k; i++) //dp 46 for(p = d[i-1].begin(); p != d[i-1].end(); p++){ 47 u = *p; 48 for(e = head[u]; e != -1; e = nxt[e]){ 49 if(w[e] == r[i]) d[i].insert(v[e]); 50 } 51 } 52 if(d[k].empty()) printf("0\n"); 53 else{ 54 printf("%d\n", d[k].size()); 55 bool first = 1; 56 for(p = d[k].begin(); p != d[k].end(); p++){ 57 if(first) first = 0; 58 else printf(" "); 59 printf("%d", *p); 60 } 61 printf("\n"); 62 } 63 } 64 65 int main() 66 { 67 while(scanf("%d", &n) == 1){ 68 init(); 69 read(); 70 solve(); 71 } 72 return 0; 73 }