noip2003题解
T1加分二叉树
描述
神经网络就是一张有向图,图中的节点称为神经元,而且两个神经
元之间至多有一条边相连,下图是一个神经元的例子:
神经元〔编号为1)
图中,X1—X3是信息输入渠道,Y1-Y2是信息输出渠道,C1表示神经元目前的状态,
Ui是阈值,可视为神经元的一个内在参数。
神经元按一定的顺序排列,构成整个神经网络。在兰兰的模型之中,神经网络中的神
经无分为几层;称为输入层、输出层,和若干个中间层。每层神经元只向下一层的神经元
输出信息,只从上一层神经元接受信息。下图是一个简单的三层神经网络的例子。
兰兰规定,Ci服从公式:(其中n是网络中所有神经元的数目)
公式中的Wji(可能为负值)表示连接j号神经元和 i号神经元的边的权值。当 Ci大于0时,该神经元处于兴奋状态,否则就处于平静状态。当神经元处于兴奋状态时,下一秒它会向其他神经元传送信号,信号的强度为Ci。
如此.在输入层神经元被激发之后,整个网络系统就在信息传输的推动下进行运作。现在,给定一个神经网络,及当前输入层神经元的状态(Ci),要求你的程序运算出最后网络输出层的状态。
格式
输入格式
输入第一行是两个整数n(1≤n≤200)和p。接下来n行,每行两个整数,第i+1行是神经元i最初状态和其阈值(Ui),非输入层的神经元开始时状态必然为0。再下面P行,每行由两个整数i,j及一个整数Wij,表示连接神经元i、j的边权值为Wij。
输出格式
输出包含若干行,每行有两个整数,分别对应一个神经元的编号,及其最后的状态,两个整数间以空格分隔。仅输出最后状态非零的输出层神经元状态,并且按照编号由小到大顺序输出!
若输出层的神经元最后状态均为 0,则输出 NULL。
限制
每个测试点1s
直接按照条件DFS跑一遍即可
vijos1105
1 #include<iostream> 2 #include<string.h> 3 #include<stdio.h> 4 #include<cstdlib> 5 #include<algorithm> 6 #define N 1000 7 using namespace std; 8 int n,m; 9 int beg[N]; 10 int flag[N]; 11 int father[N]; 12 int c[N],u[N]; 13 int cnt; 14 15 struct edge 16 { 17 int b,next,weight; 18 }E[N]; 19 20 void addedge(int a,int b,int weight) 21 { 22 E[cnt].b=b; 23 father[b]++; 24 E[cnt].next=beg[a]; 25 beg[a]=cnt; 26 E[cnt].weight=weight; 27 cnt++; 28 } 29 30 void does(int now) 31 { 32 //cout<<now<<endl; 33 //system("pause"); 34 c[now]-=u[now]; 35 flag[now]=1; 36 for(int i=beg[now];i!=-1;i=E[i].next) 37 { 38 father[E[i].b]--; 39 c[E[i].b]+=c[now]*E[i].weight; 40 } 41 } 42 43 int main() 44 { 45 memset(beg,-1,sizeof(beg)); 46 int a,b,w; 47 scanf("%d%d",&n,&m); 48 for(int i=0;i<n;i++) 49 { 50 scanf("%d%d",&c[i],&u[i]); 51 if(c[i]>0) 52 u[i]=0; 53 } 54 for(int i=0;i<m;i++) 55 { 56 scanf("%d%d%d",&a,&b,&w); 57 addedge(a-1,b-1,w); 58 } 59 while(1) 60 { 61 int mark=0; 62 for(int i=0;i<n;i++) 63 if(father[i]==0&&c[i]-u[i]>0&&flag[i]==0) 64 does(i),mark=1; 65 if(mark==0) 66 break; 67 } 68 int mark=0; 69 for(int i=0;i<n;i++) 70 if(beg[i]==-1&&c[i]>0) 71 printf("%d %d\n",i+1,c[i]),mark=1; 72 if(mark==0) 73 printf("NULL\n"); 74 return 0; 75 }
T2侦探推理
描述
明明同学最近迷上了侦探漫画《柯南》并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏。游戏的内容是这样的,明明的同学们先商量好由其中的一个人充当罪犯(在明明不知情的情况下),明明的任务就是找出这个罪犯。接着,明明逐个询问每一个同学,被询问者可能会说:
证词内容 | 证词含义 |
---|---|
I am guilty. | 我是罪犯 |
I am not guilty. | 我不是罪犯 |
XXX is guilty. | XXX 是罪犯(XXX 表示某个同学的名字) |
XXX is not guilty. | XXX 不是罪犯 |
Today is XXX. | 今天是 XXX (XXX表示星期几,是Monday Tuesday Wednesday Thursday Friday Saturday Sunday 其中之一) |
证词中出现的其他话,都不列入逻辑推理的内容。
明明所知道的是,他的同学中有N个人始终说假话,其余的人始终说真。
现在,明明需要你帮助他从他同学的话中推断出谁是真正的凶手,请记住,凶手只有一个!
格式
输入格式
输入由若干行组成,第一行有二个整数,M(1≤M≤20)、N(1≤N≤M)和P(1≤P≤100);M是参加游戏的明明的同学数,N是其中始终说谎的人数,P是证言的总数。接下来M行,每行是明明的一个同学的名字(英文字母组成,没有主格,全部大写)。往后有P行,每行开始是某个同学的名宇,紧跟着一个冒号和一个空格,后面是一句证词,符合前表中所列格式。证词每行不会超过250个字符。
输入中不会出现连续的两个空格,而且每行开头和结尾也没有空格。
输出格式
如果你的程序能确定谁是罪犯,则输出他的名字;如果程序判断出不止一个人可能是罪犯,则输出 Cannot Determine;如果程序判断出没有人可能成为罪犯,则输出 Impossible。
样例1
限制
每个测试点1s
这个T2明明就是最难的一发...TAT
而且这个题的数据貌似很萌
没有什么算法难度,就是枚举所有犯人*周几的情况判断是否可行
注意:
1.名字的长度
2.处理空格
3.有一些人可能说真话可能说假话,因此在判断是否可行的时是区间而非==
代码复杂度再创新高,以及又是一个官方数据过了但是vijos上面re的代码...
molmolmol vijos
vijos1106
1 #include<iostream> 2 #include<string.h> 3 #include<stdio.h> 4 #include<cstdlib> 5 #include<algorithm> 6 #define N 30 7 #define M 110 8 #define L 310 9 using namespace std; 10 int n,m,p; 11 char name[N][L]; 12 int is_[M][2],isnt_[M][2],today_[M][2]; 13 int cnt1,cnt2,cnt3; 14 char is[L]="is guilty.",isnt[L]="is not guilty.",mine[L]="I am guilty.",minent[L]="I am not guilty.",today[L]="Today is "; 15 char date[8][25]={"Monday.","Tuesday.","Wednesday.","Thursday.","Friday.","Saturday.","Sunday."}; 16 int ans[N]; 17 int judge[N]; 18 19 int check(int gui,int day) 20 { 21 memset(judge,0,sizeof(judge)); 22 for(int i=0;i<cnt1;i++) 23 { 24 if(is_[i][1]==gui) 25 { 26 if(judge[is_[i][0]]==0||judge[is_[i][0]]==1) 27 judge[is_[i][0]]=1; 28 else return 0; 29 } 30 else 31 { 32 if(judge[is_[i][0]]==0||judge[is_[i][0]]==2) 33 judge[is_[i][0]]=2; 34 else return 0; 35 } 36 } 37 for(int i=0;i<cnt2;i++) 38 { 39 if(isnt_[i][1]==gui) 40 { 41 if(judge[isnt_[i][0]]==0||judge[isnt_[i][0]]==2) 42 judge[isnt_[i][0]]=2; 43 else return 0; 44 } 45 else 46 { 47 if(judge[isnt_[i][0]]==0||judge[isnt_[i][0]]==1) 48 judge[isnt_[i][0]]=1; 49 else return 0; 50 } 51 } 52 for(int i=0;i<cnt3;i++) 53 { 54 if(today_[i][1]==day) 55 { 56 if(judge[today_[i][0]]==0||judge[today_[i][0]]==1) 57 judge[today_[i][0]]=1; 58 else return 0; 59 } 60 else 61 { 62 if(judge[today_[i][0]]==0||judge[today_[i][0]]==2) 63 judge[today_[i][0]]=2; 64 else return 0; 65 } 66 } 67 int tot1=0,tot2=0; 68 for(int i=0;i<n;i++) 69 { 70 if(judge[i]==2) 71 tot1++; 72 if(judge[i]==0) 73 tot2++; 74 } 75 if(p-tot1<=tot2&&tot1<=p) 76 return 1; 77 return 0; 78 } 79 80 int main() 81 { 82 char thi[L]; 83 char a; 84 int len=0; 85 scanf("%d%d%d",&n,&p,&m); 86 for(int i=0;i<n;i++) 87 scanf("%s",name[i]); 88 scanf("\n"); 89 for(int i=0;i<m;i++) 90 { 91 int x=-1,nowname=-1; 92 len=0; 93 while(1) 94 { 95 scanf("%c",&a); 96 if(a=='\n') 97 break; 98 else thi[len]=a,len++; 99 } 100 thi[len]='\0'; 101 for(int j=0;j<n;j++) 102 { 103 int mark=1; 104 for(int k=0;thi[k]!=':';k++) 105 if(thi[k]!=name[j][k]) 106 { 107 mark=0; 108 break; 109 } 110 if(mark==1) 111 { 112 x=strlen(name[j]); 113 nowname=j; 114 break; 115 } 116 } 117 int mark=1; 118 x+=2; 119 for(int j=x;j<strlen(thi);j++) 120 if(thi[j]!=mine[j-x]) 121 { 122 mark=0; 123 break; 124 } 125 if(mark==1) 126 { 127 is_[cnt1][0]=is_[cnt1][1]=nowname; 128 cnt1++; 129 continue; 130 } 131 mark=1; 132 for(int j=x;j<strlen(thi);j++) 133 if(thi[j]!=minent[j-x]) 134 { 135 mark=0; 136 break; 137 } 138 if(mark==1) 139 { 140 isnt_[cnt2][0]=isnt_[cnt2][1]=nowname; 141 cnt2++; 142 continue; 143 } 144 mark=1; 145 for(int j=x;j<strlen(today)+x;j++) 146 if(thi[j]!=today[j-x]) 147 { 148 mark=0; 149 break; 150 } 151 if(mark==1) 152 { 153 x+=strlen(today); 154 for(int j=0;j<7;j++) 155 { 156 int mar=1; 157 for(int k=x;k<strlen(date[j])+x;k++) 158 if(date[j][k-x]!=thi[k]) 159 { 160 mar=0; 161 break; 162 } 163 if(mar==1) 164 { 165 today_[cnt3][0]=nowname; 166 today_[cnt3][1]=j; 167 cnt3++; 168 break; 169 } 170 } 171 continue; 172 } 173 for(int j=0;j<n;j++) 174 { 175 int mar=1; 176 for(int k=x;thi[k]!=' ';k++) 177 if(name[j][k-x]!=thi[k]) 178 { 179 mar=0; 180 break; 181 } 182 if(mar==1) 183 { 184 int ma=1; 185 x++; 186 for(int k=strlen(name[j])+x;k<strlen(thi);k++) 187 if(is[k-strlen(name[j])-x]!=thi[k]) 188 { 189 ma=0; 190 break; 191 } 192 if(ma==1) 193 { 194 is_[cnt1][0]=nowname; 195 is_[cnt1][1]=j; 196 cnt1++; 197 break; 198 } 199 ma=1; 200 for(int k=strlen(name[j])+x;k<strlen(thi);k++) 201 if(isnt[k-strlen(name[j])-x]!=thi[k]) 202 { 203 ma=0; 204 break; 205 } 206 if(ma==1) 207 { 208 isnt_[cnt2][0]=nowname; 209 isnt_[cnt2][1]=j; 210 cnt2++; 211 break; 212 } 213 } 214 } 215 } 216 int tot=0; 217 for(int i=0;i<n;i++) 218 { 219 for(int j=0;j<7;j++) 220 if(check(i,j)==1) 221 ans[i]=1; 222 if(ans[i]==1) 223 tot++; 224 } 225 if(tot==0) 226 cout<<"Impossible"<<endl; 227 else if(tot>1) 228 cout<<"Cannot Determine"<<endl; 229 else 230 for(int i=0;i<n;i++) 231 if(ans[i]==1) 232 cout<<name[i]<<endl; 233 return 0; 234 }
T3加分二叉树
描述
设一个n个节点的二叉树tree的中序遍历为(l,2,3,…,n),其中数字1,2,3,…,n为节点编号。每个节点都有一个分数(均为正整数),记第i个节点的分数为di,tree及它的每个子树都有一个加分,任一棵子树subtree(也包含tree本身)的加分计算方法如下:
subtree的左子树的加分× subtree的右子树的加分+subtree的根的分数
若某个子树为空,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空子树。
试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树tree。要求输出;
(1)tree的最高加分
(2)tree的前序遍历
格式
输入格式
第1行:一个整数n(n<30),为节点个数。
第2行:n个用空格隔开的整数,为每个节点的分数(分数<100)。
输出格式
第1行:一个整数,为最高加分(结果不会超过4,000,000,000)。
第2行:n个用空格隔开的整数,为该树的前序遍历。
限制
每个测试点1s
一棵子树在中序遍历上是连续一段,所以我们只需要区间dp并记录父亲节点,最后DFS输出即可
vijos1100
1 #include<iostream> 2 #include<string.h> 3 #include<stdio.h> 4 #include<cstdlib> 5 #include<algorithm> 6 #define N 35 7 using namespace std; 8 int n; 9 long long number[N]; 10 long long answer[N][N]; 11 int father[N][N]; 12 13 void DFS(int l,int r) 14 { 15 //cout<<l<<" "<<r<<endl; 16 //system("pause"); 17 if(l>r) 18 return ; 19 if(l==r) 20 { 21 cout<<l+1<<" "; 22 return ; 23 } 24 cout<<father[l][r]+1<<" "; 25 DFS(l,father[l][r]-1); 26 DFS(father[l][r]+1,r); 27 } 28 29 int main() 30 { 31 scanf("%d",&n); 32 for(int i=0;i<n;i++) 33 scanf("%d",&number[i]); 34 for(int i=0;i<n;i++) 35 answer[i][i]=number[i],father[i][i]=i; 36 for(int l=1;l<n;l++) 37 for(int i=0;i+l<n;i++) 38 { 39 int j=i+l; 40 for(int k=i+1;k<=j-1;k++) 41 if(answer[i][k-1]*answer[k+1][j]+number[k]>answer[i][j]) 42 answer[i][j]=answer[i][k-1]*answer[k+1][j]+number[k],father[i][j]=k; 43 if(answer[i][i]+answer[i+1][j]>answer[i][j]) 44 answer[i][j]=answer[i][i]+answer[i+1][j],father[i][j]=i; 45 } 46 cout<<answer[0][n-1]<<endl; 47 DFS(0,n-1); 48 return 0; 49 }
T4传染病防治
描述
研究表明,这种传染病的传播具有两种很特殊的性质;
第一是它的传播途径是树型的,一个人X只可能被某个特定的人Y感染,只要Y不
得病,或者是XY之间的传播途径被切断,则X就不会得病。
第二是,这种疾病的传播有周期性,在一个疾病传播周期之内,传染病将只会感染一
代患者,而不会再传播给下一代。
这些性质大大减轻了蓬莱国疾病防控的压力,并且他们已经得到了国内部分易感人群
的潜在传播途径图(一棵树)。但是,麻烦还没有结束。由于蓬莱国疾控中心人手不够,同时也缺乏强大的技术,以致他们在一个疾病传播周期内,只能设法切断一条传播途径,而没有被控制的传播途径就会引起更多的易感人群被感染(也就是与当前已经被感染的人有传播途径相连,且连接途径没有被切断的人群)。当不可能有健康人被感染时,疾病就中止传播。所以,蓬莱国疾控中心要制定出一个切断传播途径的顺序,以使尽量少的人被感染。你的程序要针对给定的树,找出合适的切断顺序。
格式
输入格式
输入格式的第一行是两个整数n(1≤n≤300)和p。接下来p行,每一行有两个整数i
和j,表示节点i和j间有边相连(意即,第i人和第j人之间有传播途径相连)。其中节点
1是已经被感染的患者。
输出格式
只有一行,输出总共被感染的人数。
限制
每个测试点1s
考虑数据范围..搜索即可
vijos1101
1 #include<iostream> 2 #include<string.h> 3 #include<stdio.h> 4 #include<cstdlib> 5 #include<algorithm> 6 #define N 305 7 #define inf 0x3f3f3f3f 8 using namespace std; 9 int n,m; 10 int beg[N*2]; 11 int father[N]; 12 int cnt; 13 int flag[N]; 14 int ans=inf; 15 16 struct edge 17 { 18 int b,next; 19 }E[N*2]; 20 21 void addedge(int a,int b) 22 { 23 E[cnt].b=b; 24 E[cnt].next=beg[a]; 25 beg[a]=cnt; 26 cnt++; 27 E[cnt].b=a; 28 E[cnt].next=beg[b]; 29 beg[b]=cnt; 30 cnt++; 31 } 32 33 void DFS(int now) 34 { 35 for(int i=beg[now];i!=-1;i=E[i].next) 36 if(E[i].b!=father[now]) 37 { 38 father[E[i].b]=now; 39 DFS(E[i].b); 40 } 41 } 42 43 void does(int deep) 44 { 45 int now[N]; 46 for(int i=0;i<n;i++) 47 now[i]=flag[i]; 48 if(deep>=ans) 49 return ; 50 int mark=1; 51 int tot=0; 52 for(int i=0;i<n;i++) 53 if(flag[i]==1) 54 flag[i]=2; 55 for(int i=0;i<n;i++) 56 if(flag[i]==2) 57 for(int j=beg[i];j!=-1;j=E[j].next) 58 if(E[j].b!=father[i]) 59 if(flag[E[j].b]==0) 60 flag[E[j].b]=1,tot++; 61 for(int i=0;i<n;i++) 62 if(flag[i]==2) 63 for(int j=beg[i];j!=-1;j=E[j].next) 64 if(E[j].b!=father[i]) 65 if(flag[E[j].b]==1) 66 { 67 flag[E[j].b]=3; 68 mark=0; 69 does(deep+tot-1); 70 flag[E[j].b]=1; 71 } 72 for(int i=0;i<n;i++) 73 flag[i]=now[i]; 74 if(mark==1) 75 { 76 ans=min(ans,deep); 77 return ; 78 } 79 } 80 81 int main() 82 { 83 memset(beg,-1,sizeof(beg)); 84 int a,b; 85 scanf("%d%d",&n,&m); 86 for(int i=0;i<n-1;i++) 87 scanf("%d%d",&a,&b),addedge(a-1,b-1); 88 DFS(0); 89 flag[0]=1; 90 does(1); 91 printf("%d\n",ans); 92 return 0; 93 }