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。

样例1

样例输入1[复制]

 
5 6
1 0
1 0
0 1
0 1
0 1
1 3 1
1 4 1
1 5 1
2 3 1
2 4 1
2 5 1

样例输出1[复制]

 
3 1
4 1
5 1

限制

每个测试点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

样例输入1[复制]

 
3 1 5
MIKE
CHARLES
KATE
MIKE: I am guilty.
MIKE: Today is Sunday.
CHARLES: MIKE is guilty.
KATE: I am guilty.
KATE: How are you??

样例输出1[复制]

 
MIKE

限制

每个测试点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个用空格隔开的整数,为该树的前序遍历。

样例1

样例输入1[复制]

 
5
5 7 1 2 10

样例输出1[复制]

 
145
3 1 2 4 5

限制

每个测试点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是已经被感染的患者。

输出格式

只有一行,输出总共被感染的人数。

样例1

样例输入1[复制]

 
7 6
1 2
1 3
2 4
2 5
3 6
3 7

样例输出1[复制]

 
3

限制

每个测试点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 }

 

转载于:https://www.cnblogs.com/zyx45889/p/6071519.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值