题目记录
1 //二分+DP 2 #include<iostream> 3 #include<algorithm> 4 #define N 20010 5 using namespace std; 6 int n,ans,a[N],maxn[N],minn[N],l,r; 7 bool dp(int x){ 8 maxn[1]=minn[1]=a[1]; 9 for(int i=2;i<=n;i++){ 10 maxn[i]=min(a[i],a[1]-minn[i-1]); 11 minn[i]=max(0,a[i]-(x-a[i-1]-a[1]+maxn[i-1])); 12 } 13 if(!minn[n]) return 1; 14 else return 0; 15 } 16 int main() 17 { 18 ios::sync_with_stdio(false); //cin加速 19 cin>>n; 20 for(int i=1;i<=n;i++){ 21 cin>>a[i]; 22 if(i>=2) l=max(l,a[i]+a[i-1]); 23 if(i>=3) r=max(r,a[i]+a[i-1]+a[i-2]); 24 } 25 l=max(l,a[1]+a[n]); 26 r=max(max(r,a[n]+a[1]+a[2]),a[n-1]+a[n]+a[1]); 27 ans=r; 28 while(l<=r){ 29 int mid=(l+r)>>1; 30 if(!dp(mid)){ 31 l=mid+1; 32 } 33 else { 34 ans=min(ans,mid); 35 r=mid-1; 36 } 37 } 38 cout<<ans; 39 return 0; 40 } //注意大括号 英汉相貌一模一样 41 /* 42 //贪心(乱搞) 43 #include<iostream> 44 #include<cmath> 45 #include<algorithm> 46 #define N 20010 47 using namespace std; 48 int n,ans,a[N],l; 49 double sum,nn; 50 int main() 51 { 52 ios::sync_with_stdio(false); //cin加速 53 cin>>n; 54 for(int i=1;i<=n;i++){ 55 cin>>a[i]; 56 if(i>=2) l=max(l,a[i]+a[i-1]); 57 sum+=a[i]; 58 } 59 l=max(l,a[1]+a[n]); 60 nn=n; //不可以sum*2/n,(n/2)自动向下取整 61 cout<<max(l,(int)ceil(sum/(n/2))); //ceil向上取整函数类型为double 62 return 0; //floor 向下取整 63 } 64 */
2019-09-24
小模拟赛
1 //100 O(n) 若两个数相减%7==0,那么这两个数%7的余数一定相同!! 2 #include<cstdio> 3 #include<algorithm> 4 #define in inline 5 using namespace std; 6 in int read(){ 7 int x=0,f=1; char c=getchar(); 8 while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();} 9 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 10 return f*x; 11 } 12 int sum[50010],first[10],last[10],ans,n; 13 int main() 14 { 15 n=read(); 16 for(int i=1;i<=n;i++){ 17 int x=read(); 18 sum[i]=(sum[i-1]+x)%7; 19 } 20 for(int i=n;i>=1;i--) first[sum[i]]=i; 21 for(int i=1;i<=n;i++) last[sum[i]]=i; 22 for(int i=0;i<7;i++) ans=max(ans,last[i]-first[i]); // 7的余数:0~6 23 printf("%d",ans); 24 return 0; 25 } 26 //70 O(n^2) 27 /* 考试代码 28 #include<cstdio> 29 #include<algorithm> 30 #define in inline 31 using namespace std; 32 in int read(){ 33 int x=0,f=1; char c=getchar(); 34 while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();} 35 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 36 return f*x; 37 } 38 int sum[50010],ans,n; 39 int main() 40 { 41 n=read(); 42 int x=read(); 43 sum[1]=x%7; 44 for(int i=2;i<=n;i++){ 45 x=read(); 46 sum[i]=sum[i-1]+(x%7); 47 } 48 for(int i=1;i<=n;i++) 49 for(int j=0;j<i;j++){ 50 if((sum[i]-sum[j])%7==0) ans=max(ans,i-j); 51 } 52 printf("%d",ans); 53 return 0; 54 } 55 */
2. 抓住那头牛
1 #include<cstdio> 2 #include<queue> 3 #include<cstring> 4 #define N 100000 5 using namespace std; 6 int a,b,t[100010]; 7 queue <int > q; 8 int main() 9 { 10 scanf("%d%d",&a,&b); 11 memset(t,-1,sizeof(t)); 12 q.push(a); 13 t[a]=0; 14 while(!q.empty()){ 15 int u=q.front(); 16 q.pop(); 17 if(u==b){ 18 printf("%d",t[b]); 19 return 0; 20 } 21 if(u*2<=N){ 22 if(t[u*2]<0){ 23 t[u*2]=t[u]+1; 24 q.push(u*2); 25 } 26 } 27 if(u+1<=N){ 28 if(t[u+1]<0){ 29 t[u+1]=t[u]+1; 30 q.push(u+1); 31 } 32 } 33 if(u-1>=0){ 34 if(t[u-1]<0){ 35 t[u-1]=t[u]+1; 36 q.push(u-1); 37 } 38 } 39 } 40 return 0; 41 }
2019-10-15
小模拟赛
1. P1288 取数游戏II 贪心 博弈论
题目描述
有一个取数的游戏。初始时,给出一个环,环上的每条边上都有一个非负整数。这些整数中至少有一个0。然后,将一枚硬币放在环上的一个节点上。两个玩家就是以这个放硬币的节点为起点开始这个游戏,两人轮流取数,取数的规则如下:
(1)选择硬币左边或者右边的一条边,并且边上的数非0;
(2)将这条边上的数减至任意一个非负整数(至少要有所减小);
(3)将硬币移至边的另一端。
如果轮到一个玩家走,这时硬币左右两边的边上的数值都是0,那么这个玩家就输了。
如下图,描述的是Alice和Bob两人的对弈过程,其中黑色节点表示硬币所在节点。结果图(d)中,轮到Bob走时,硬币两边的边上都是0,所以Alcie获胜。
(a)Alice (b)Bob (c)Alice (d)Bob
现在,你的任务就是根据给出的环、边上的数值以及起点(硬币所在位置),判断先走方是否有必胜的策略。
输入格式
第一行一个整数N(N≤20),表示环上的节点数。
第二行N个数,数值不超过30,依次表示N条边上的数值。硬币的起始位置在第一条边与最后一条边之间的节点上。
输出格式
仅一行。若存在必胜策略,则输出“YES”,否则输出“NO”。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 int read(){ 5 int x=0,f=1; char c=getchar(); 6 while(c<'0'||c>'9') {if(c=='-')f=-1; c=getchar();} 7 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 8 return x*f; 9 10 } 11 int n,a[2010],f[1010],k,ans1,ans2; 12 int main() 13 { 14 //freopen("yx.in","r",stdin); 15 //freopen("yx.out","w",stdout); 16 n=read(); 17 for(int i=1;i<=n;i++){ 18 a[i]=read(),a[n+i]=a[i],a[2*n+i]=a[i]; 19 if(a[i]!=0) k=1; 20 } 21 //printf("* %d ",k); 22 if(k==0||(a[1]==0&&a[n]==0)){ 23 printf("NO"); 24 return 0; 25 } 26 for(int i=n+1;i<=n*2;i++) 27 if(a[i]==0){ 28 if(a[i-1]!=0){ 29 if((i-1)%n!=0) 30 f[(i-1)%n]=1;///printf("* %d",(i-1)%n); 31 else f[n]=1; 32 } 33 if(a[i+1]!=0){ 34 if((i+1)%n!=0) 35 f[(i+1)%n]=1;//printf("* %d",(i+1)%n); 36 else f[n]=1; 37 } 38 } 39 for(int i=1;i<=n;i++){ 40 ans1++; 41 if(f[i]==1) break; 42 } 43 for(int i=2*n;i>n;i--){ //倒着循环 70->100 对拍检验!!!
44 ans2++; 45 if(i==n&&f[i]==1) break; 46 else if(f[i%n]==1) break; 47 } 48 //printf("& %d %d ",ans1,ans2); 49 if(ans1%2==1||ans2%2==1) printf("YES"); 50 else printf("NO"); 51 //fclose(stdin); 52 //fclose(stdout); 53 return 0; 54 } 55 //思路先咕着
2. P3183 [HAOI2016]食物链 dfs跑图
题目描述
如图所示为某生态系统的食物网示意图,据图回答第1小题现在给你n个物种和m条能量流动关系,求其中的食物链条数。
物种的名称为从1到n编号M条能量流动关系形如a1 b1a2 b2a3 b3......am-1 bm-1am bm其中ai bi表示能量从物种ai流向物种bi。
注意单独的一种孤立生物不算一条食物链。
输入格式
第一行两个整数n和m,接下来m行每行两个整数ai bi描述m条能量流动关系。(数据保证输入数据符号生物学特点,且不会有重复的能量流动关系出现)1<=N<=100000 0<=m<=200000题目保证答案不会爆 int
输出格式
一个整数即食物网中的食物链条数。
1 #include<cstdio> 2 #define N 100010 3 #define M 200010 4 using namespace std; 5 int read(){ 6 int x=0,f=1; char c=getchar(); 7 while(c<'0'||c>'9') {if(c=='-')f=-1; c=getchar();} 8 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 9 return x*f; 10 } 11 struct node{ 12 int to,next; 13 }way[M*2]; 14 int n,m,cnt,ans; 15 int f[N],head[M*2],cd[N],rd[N]; 16 void add(int x,int y){ 17 way[++cnt].next=head[x]; 18 way[cnt].to=y; 19 head[x]=cnt; 20 } 21 int dfs(int x){ 22 int sum=0; 23 if(f[x]) return f[x]; 24 if(!cd[x]&&rd[x]) sum++; 25 for(int i=head[x];i;i=way[i].next){ 26 int y=way[i].to; 27 sum+=dfs(y); 28 } 29 f[x]=sum; 30 return sum; 31 } 32 int main() 33 { 34 n=read(),m=read(); 35 for(int i=1;i<=m;i++){ 36 int u=read(),v=read(); 37 cd[u]++,rd[v]++; 38 add(u,v); 39 } 40 for(int i=1;i<=n;i++) if(!rd[i]) ans+=dfs(i); 41 printf("%d",ans); 42 return 0; 43 }
3. 注意二分上下界限,下界也可能是最大值
4. P1726 上白泽慧音 tarjan缩点(见图论tarjan专题)
2019-10-19
1.最长不下降子序列
1 /* 2 本质:c[i]=b[a[i]] 3 以a序列为下标,重组b序列->c序列 4 问题转换成: 找c序列的最长不下降子序列 5 */ 6 #include<cstdio> 7 #include<algorithm> 8 #define N 50010 9 using namespace std; 10 const int inf=1e9+7; 11 int n,ans; 12 int b[N],c[N],d[N]; 13 int main() 14 { 15 scanf("%d",&n); 16 for(int x,i=1;i<=n;i++) //下标即位置。 17 scanf("%d",&x),b[x]=i,d[i]=inf;//"b[x]=i"将b序列里的数与其位置互换 18 for(int a,i=1;i<=n;i++) 19 scanf("%d",&a),c[i]=b[a]; 20 for(int i=1;i<n;i++){ 21 int k=lower_bound(d+1,d+1+n,c[i])-d;//找第一个>=c[i]的数 22 ans=max(ans,k); 23 d[k]=c[i]; 24 } 25 printf("%d",ans); 26 return 0; 27 }
2. 某种密码(待修改)
1 #include<cstdio> 2 #include<algorithm> 3 #define ll long long 4 #define N 100 5 using namespace std; 6 int n,mid,ans,i,j,cnta,cntb; 7 ll key; 8 ll a[N],b[N],s[N]; 9 void dfs(int pos,ll sum,int t){ 10 if(pos==mid+1&&t==1){ 11 a[++cnta]=sum; 12 return ; 13 } 14 if(pos==n+1){ 15 b[++cntb]=sum; 16 return ; 17 } 18 dfs(pos+1,sum+s[pos],t); 19 dfs(pos+1,sum,t); 20 } 21 int main() 22 { 23 scanf("%d%lld",&n,&key); 24 for(int i=1;i<=n;i++) scanf("%d",&s[i]); 25 mid=(1+n)>>1; 26 dfs(1,(ll)0,1),dfs(mid+1,(ll)0,2); 27 sort(a+1,a+1+cnta); 28 sort(b+1+cntb,b+1); 29 i=j=1; 30 while(i<=mid&&j<=n){ 31 if(a[i]+b[j]==key){ 32 int kb=1,ka=upper_bound(a+1+i,a+1+n,a[i])-a-1-i; 33 i+=ka,j++; 34 while(b[j]==b[j-1]) kb++,j++; 35 ans+=ka*kb; 36 } 37 else if(a[i]+b[j]<key){ 38 while(b[j]==b[j+1]) j++; 39 j++; 40 } 41 else{ 42 int ka=upper_bound(a+1+i,a+1+n,a[i])-a-1-i; 43 i+=ka; 44 } 45 } 46 printf("%lld",ans); 47 return 0; 48 }
1. 不能打到最后一刻。打完程序保存保存保存 -> 关闭编译器 -> 打开检查文件检查 -> 放入文件夹
2. 检查输出是否遵循格式,如:“ ”
3. 注意开 long long
窝今天真的太惨太惨了.......
2019-10-31
1.小猫爬山
题面:
Freda和rainbow饲养了N只小猫,这天,小猫们要去爬山。经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了(呜咕>_<)。
Freda和rainbow只好花钱让它们坐索道下山。索道上的缆车最大承重量为W,而N只小猫的重量分别是C1、C2……CN。
当然,每辆缆车上的小猫的重量之和不能超过W。每租用一辆缆车,Freda和rainbow就要付1美元,所以他们想知道,最少需要付多少美元才能把这N只小猫都运送下山?
1 /*考场贪心 75分 2 从小到大排序 3 从大到小都尝试塞进第一个缆车里 4 从大到小都尝试塞进第二个缆车里 5 ...... 6 直到塞完。 7 ----------------------------------------- 8 看似很完美,实际有问题。 9 追求前面缆车的效率,忽视了最后的缆车的空余 10 应追求总体效率 11 可尝试以下hack数据观察问题 12 */ 13 #include<cstdio> 14 #include<algorithm> 15 #include<iostream> 16 #define re register 17 #define in inline 18 #define ll long long 19 #define N 50 20 using namespace std; 21 in int read(){ 22 int x=0,f=1; char c=getchar(); 23 while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} 24 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 25 return x*f; 26 } 27 int n,w,ans; 28 int c[N],vis[N]; 29 ll sum; 30 int main() 31 { 32 //freopen("catclimb.in","r",stdin); 33 //freopen("catclimb.out","w",stdout); 34 n=read(),w=read(); 35 for(re int i=1;i<=n;i++) c[i]=read(),sum+=c[i]; 36 if(sum<=w){ 37 printf("%d",1); 38 return 0; 39 } 40 sort(c+1,c+1+n); 41 for(re int i=n;i>=1;i--) printf("* %d ",c[i]); 42 printf(" "); 43 for(re int i=n;i>=1;i--){ 44 if(vis[i]) continue; 45 int s=c[i]; 46 printf("& %d ",c[i]); 47 vis[i]=1; 48 if(w>s){ 49 for(re int j=i-1;j>=1;j--){ 50 if(s+c[j]<=w&&!vis[j]){ 51 s+=c[j]; 52 printf("& %d ",c[j]); 53 vis[j]=1; 54 } 55 } 56 } 57 printf(" "); 58 ans+=1; 59 } 60 printf("%d",ans); 61 return 0; 62 } 63 /* 64 18 100000000 65 37597832 66 24520955 67 100000000 68 18509980 69 29141223 70 20287969 71 14028193 72 33097076 73 12116817 74 53439913 75 10216168 76 32891936 77 43952038 78 13463011 79 4056577 80 4646046 81 10153053 82 37881213 83 */
1 /* 2 满分迭代深搜 3 -------------- 4 枚举缆车数 5 尝试每一种情况 6 保证最优解 7 */ 8 #include<cstdio> 9 #include<algorithm> 10 #include<iostream> 11 #define re register 12 #define in inline 13 #define ll long long 14 #define N 50 15 using namespace std; 16 in int read(){ 17 int x=0,f=1; char c=getchar(); 18 while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} 19 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 20 return x*f; 21 } 22 int n,w,deep; 23 int c[N],b[N]; 24 ll sum; 25 bool flag; 26 void dfs(int x){ 27 if(x==n+1) {flag=1; return ;} 28 for(int i=1;i<=deep;i++) 29 if(b[i]+c[x]<=w){ 30 b[i]+=c[x]; 31 dfs(x+1); 32 b[i]-=c[x]; 33 if(flag) return ; 34 } 35 } 36 int main() 37 { 38 n=read(),w=read(); 39 for(re int i=1;i<=n;i++) c[i]=read(),sum+=c[i]; 40 if(sum<=w){ 41 printf("1"); 42 return 0; 43 } 44 sort(c+1,c+1+n,greater<int>()); 45 for(deep=sum/w;deep<=18;deep++){ 46 dfs(1); 47 if(flag){ 48 printf("%d",deep); 49 return 0; 50 } 51 } 52 return 0; 53 }
小模拟赛
潜伏者
题目描述
密码的编码规则:
1. 原信息与加密后内容均 由大写字母‘A’-‘Z’构成 (无空格等其他字符)。
2. S国对于每个字母规定了对应的“密字”。加密的过程就是将原信息中的所有字母替换为其对应的“密字”。
3. 每个字母只对应一个唯一的“密字”,不同的字母对应不同的“密字”。“密字”可以和原字母相同。
例如,若规定‘A’的密字为‘A’,‘B’的密字为‘C’(其他字母及密字略),则原信息“ABAABA”被加密为“ACAACA”。
破译过程:停止于如下的某个状态:
1. 所有信息扫描完毕,‘A’-‘Z’ 所有 26个字母在原信息中均出现过并获得了相应的“密字”。
2. 所有信息扫描完毕,但发现存在某个(或某些)字母在原信息中没有出现。
3. 扫描中发现掌握的信息里有明显的自相矛盾或错误(违反 S 国密码的编码规则)。例如某条信息“XYZ”被翻译为“ABA”就违反了“不同字母对应不同密字”的规则。
注意审题!!! 像这样细碎的条件可以先列在纸上,避免遗忘!
输入格式
共 3行,每行为一个长度在 11到 100100之间的字符串。
第1 行为小 C 掌握的一条加密信息。
第2 行为第 1 行的加密信息所对应的原信息。
第3 行为 R国司令部要求小C 翻译的加密信息。
输入数据保证所有字符串仅由大写字母‘A’-‘Z’构成,且第 1行长度与第 22行相等。
输出格式
共 1 行。
若破译密码停止时出现 2,3 两种情况,请你输出“Failed”(不含引号,注意首字母大
写,其它小写)。
否则请输出利用密码翻译电报中加密信息后得到的原信息。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define re register 6 #define in inline 7 #define ll long long 8 using namespace std; 9 char s1[110],s2[110],s3[110]; 10 int a[1010],len1,len2,len3; 11 int main() 12 { 13 //freopen("qfz.in","r",stdin); 14 //freopen("qfz.out","w",stdout); 15 cin>>s1>>s2>>s3; 16 len1=strlen(s1); 17 len2=strlen(s2); 18 len3=strlen(s3); 19 if(len1<26||len2<26||len1!=len2) printf("Failed"); 20 else{ 21 for(re int i=0;i<len1;i++){ 22 int x=s1[i]-'0',y=s2[i]-'0'; 23 if(!a[x]) a[x]=y; 24 else if(a[x]!=y){ 25 printf("Failed"); 26 return 0; 27 } 28 } 29 for(re int i=0;i<26;i++) 30 for(re int j=0;j<26;j++){ 31 if(!a['A'+i-'0']){ 32 printf("Failed"); 33 return 0; 34 } 35 if(i!=j&&a['A'+i-'0']==a['A'+j-'0']){ 36 printf("Failed"); 37 return 0; 38 } 39 } 40 for(int i=0;i<len3;i++){ 41 printf("%c",a[s3[i]-'0']+'0'); 42 } 43 } 44 return 0; 45 }
3.吃火腿
题面:小月言想切最少的刀数,使这n根火腿分成均等的m份。请问最少要切几刀?
1 /* 2 可以把n根火腿肠连起来,那么最多需要切m-1刀,如果下刀处恰好是火腿的连接处,那么就少切一刀 3 最少需要切0刀(n是m的倍数) 4 所以,ans=max(m-gcd(n,m),0); 5 */ 6 #include<cstdio> 7 #include<cstring> 8 #include<iostream> 9 #define re register 10 #define in inline 11 using namespace std; 12 in int read(){ 13 int x=0,f=1; char c=getchar(); 14 while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} 15 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 16 return x*f; 17 } 18 int gcd(int a,int b){ 19 return b? gcd(b,a%b): a; 20 } 21 int main() 22 { 23 int T=read(); 24 while(T--){ 25 int n=read(),m=read(); 26 if(!(n%m)) printf("0 "); 27 else printf("%d ",m-gcd(n,m)); 28 } 29 return 0; 30 }
2019-11-11
P1041 传染病控制 【搜索】
题目描述
传染病的传播具有两种很特殊的性质:
第一 传播途径是树型的,一个人X只可能被某个特定的人Y感染,只要Y不得病,或者是XY之间的传播途径被切断,则X就不会得病。
第二 这种疾病的传播有周期性,在一个疾病传播周期之内,传染病将只会感染一代患者,而不会再传播给下一代。
这些性质大大减轻了蓬莱国疾病防控的压力,并且他们已经得到了国内部分易感人群的潜在传播途径图(一棵树)。若在一个疾病传播周期内,只能切断一条传播途径,而没有被控制的传播途径就会引起更多的易感人群被感染(也就是与当前已经被感染的人有传播途径相连,且连接途径没有被切断的人群)。当不可能有健康人被感染时,疾病就中止传播。所以,蓬莱国疾控中心要制定出一个切断传播途径的顺序,以使尽量少的人被感染。
你的程序要针对给定的树,找出合适的切断顺序。
输入格式
第一行是两个整数n(1≤n≤300)和p。
接下来p行,每一行有2个整数i和j,表示节点i和j间有边相连。(意即,第i人和第j人之间有传播途径相连)。其中节点1是已经被感染的患者。
输出格式
1行,总共被感染的人数。
1 #include<cstdio> 2 #include<vector> 3 #include<algorithm> 4 #define re register 5 #define N 310 6 #define in inline 7 #define ll long long 8 using namespace std; 9 int read(){ 10 int x=0,f=1; char c=getchar(); 11 while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();} 12 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 13 return x*f; 14 } 15 struct node{ 16 int next,to; 17 }edge[N*2]; 18 int n,m,cnt,ans; 19 int head[N*2],fa[N],siz[N],deep[N],depm,vis[N]; 20 vector <int > k[N]; 21 22 in void add(int x,int y){ 23 edge[++cnt].next=head[x]; 24 edge[cnt].to=y; 25 head[x]=cnt; 26 } 27 void dfs1(int x,int f,int dep){ 28 fa[x]=f,deep[x]=dep,siz[x]=1; 29 depm=max(depm,dep); 30 for(int i=head[x];i;i=edge[i].next){ 31 int v=edge[i].to; 32 if(v!=f){ 33 dfs1(v,x,dep+1); 34 siz[x]+=siz[v]; 35 } 36 } 37 } 38 void dfs2(int dep,int now){ 39 if(dep==depm+1){ // dfs结束的状态 1: 搜到比最深deep更深的一层 40 ans=min(ans,now); 41 return ; 42 } 43 for(int i=0;i<k[dep].size();i++) //每次进入下一层时,扫 fa,如果fa被标记,则该点也被标记 44 if(vis[fa[k[dep][i]]]) vis[k[dep][i]]=1; 45 else vis[k[dep][i]]=0; 46 bool f=1; 47 for(int i=0;i<k[dep].size();i++) 48 if(!vis[k[dep][i]]) f=0; 49 if(f){ //dfs结束的状态 2: 搜到某层时该层的点已全部被打上标记 50 ans=min(ans,now); 51 return ; 52 } 53 for(int i=0;i<k[dep].size();i++){ 54 if(vis[k[dep][i]]) continue; 55 vis[k[dep][i]]=1; //切断某个点与fa的连线表示该点打上标记,表示不被感染,并减去该点size 56 dfs2(dep+1,now-siz[k[dep][i]]); 57 vis[k[dep][i]]=0; 58 } 59 } 60 int main() 61 { 62 n=read(),m=read(); 63 for(re int i=1;i<=m;i++){ 64 int u=read(),v=read(); 65 add(u,v),add(v,u); 66 } 67 dfs1(1,0,1); //预处理出每个点的 size,fa,deep 68 69 for(re int i=1;i<=n;i++) 70 k[deep[i]].push_back(i); //按照 deep将每个点存入 vector中 71 72 ans=n,dfs2(2,n); //按照 deep进行 dfs2求解答案 73 printf("%d",ans); 74 return 0; 75 }
P3916 图的遍历
题目描述
给出N个点,M条边的有向图,对于每个点v,求A(v)表示从点v出发,能到达的编号最大的点。
奇技淫巧之反向建边!
1 #include<cstdio> 2 #include<queue> 3 #define N 100010 4 #define re register 5 #define in inline 6 using namespace std; 7 in int read(){ 8 int x=0,f=1; char c=getchar(); 9 while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();} 10 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 11 return x*f; 12 } 13 struct node{ 14 int next,to; 15 }edge[N]; 16 int n,m,cnt; 17 int vis[N],head[N]; 18 queue <int > q; 19 20 in void add(int u,int v){ 21 edge[++cnt].next=head[u]; 22 edge[cnt].to=v; 23 head[u]=cnt; 24 } 25 void bfs(int x){ 26 while(!q.empty()){ 27 int u=q.front(); 28 q.pop(); 29 vis[u]=x; 30 for(int i=head[u];i;i=edge[i].next){ 31 int v=edge[i].to; 32 if(!vis[v]) q.push(v); 33 } 34 } 35 } 36 int main() 37 { 38 n=read(),m=read(); 39 for(re int i=1;i<=m;i++){ 40 int u=read(),v=read(); 41 add(v,u); 42 } 43 for(re int i=n;i>=1;i--){ 44 if(vis[i]) continue; 45 46 q.push(i),bfs(i); 47 } 48 49 for(re int i=1;i<=n;i++) 50 printf("%d ",vis[i]); 51 return 0; 52 }