标签:胜利 over hang def 优化 queue org 没有 例子
翻转游戏是在一个 4×4的正方形上进行的,在正方形的 个格上每个格子都放着一个双面的物件。每个物件的两个面,一面是白色,另一面是黑色,每个物件要么白色朝上,要么黑色朝上,每一次你只能翻 个物件,从而由黑到白的改变这些物件上面的颜色,反之亦然。每一轮被选择翻转的物件遵循以下规则:
bwbw wwww bbwb bwwb
这里b表示该格子放的物件黑色朝上,w表示该格子白色朝上。如果我们选择翻转第三行第一件物件,那么格子状态将变为
bwbw bwww wwwb wwwb
游戏的目标是翻转所有的物件白色朝上或黑色朝上。你的任务就是写一个程序来求最少的的翻转次数来实现这一目标。
输入格式
bwwb bbwb bwwb bwww
4
暴力枚举
1 #include<bits/stdc++.h> 2 using namespace std; 3 char s[5]; 4 int a[18],b[18]; 5 int sum,ans=1e7; 6 void change(int i){ 7 b[i]^=1; 8 sum++; 9 if(i>=5)b[i-4]^=1; 10 if(i<=12)b[i+4]^=1; 11 if(i%4!=1)b[i-1]^=1; 12 if(i%4!=0)b[i+1]^=1; 13 } 14 15 bool j(){ 16 int cnt=0; 17 for(int i=1;i<=16;i++){ 18 cnt+=b[i]; 19 } 20 if(cnt==0||cnt==16)return 1; 21 else return 0; 22 } 23 24 int main(){ 25 for(int i=1;i<=4;i++){ 26 scanf("%s",s+1); 27 for(int j=1;j<=4;j++){ 28 if(s[j]==‘b‘)a[(i-1)*4+j]=1; 29 } 30 } 31 int maxn=1<<16; 32 for(int s=0;s<maxn;s++){ 33 for(int i=1;i<=16;i++){ 34 b[i]=a[i]; 35 } 36 sum=0; 37 for(int i=1;i<=16;i++){ 38 if(s&(1<<(i-1))){ 39 change(i); 40 } 41 } 42 if(j())ans=min(ans,sum); 43 } 44 if(ans==1e7)printf("Impossible\n"); 45 else printf("%d\n",ans); 46 return 0; 47 }
Siruseri 城中的道路都是单向的。不同的道路由路口连接。按照法律的规定,在每个路口都设立了一个 Siruseri 银行的 ATM 取款机。令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧。
Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫。他将从市中心出发,沿着单向道路行驶,抢劫所有他途径的 ATM 机,最终他将在一个酒吧庆祝他的胜利。
使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的现金数额。他希望你帮助他计算从市中心出发最后到达某个酒吧时最多能抢劫的现金总数。他可以经过同一路口或道路任意多次。但只要他抢劫过某个 ATM 机后,该 ATM 机里面就不会再有钱了。 例如,假设该城中有 666 个路口,道路的连接情况如下图所示:
市中心在路口 1,由一个入口符号 → 来标识,那些有酒吧的路口用双圈来表示。每个 ATM 机中可取的钱数标在了路口的上方。在这个例子中,Banditji 能抢劫的现金总数为 47,实施的抢劫的路线为1-2-4-1-2-3-5。
第一行包含两个整数 N,M。N表示路口的个数,M表示道路条数。
接下来 M行,每行两个整数,这两个整数都在 1 到 N之间,第 i+1行的两个整数表示第 i条道路的起点和终点的路口编号。
接下来 N行,每行一个整数,按顺序表示每个路口处的 ATM 机中的钱数 ai。
接下来一行包含两个整数 S,P,S表示市中心的编号,也就是出发的路口。P表示酒吧数目。
接下来的一行中有 P个整数,表示 P个有酒吧的路口的编号。
输出一个整数,表示 Banditji 从市中心开始到某个酒吧结束所能抢劫的最多的现金总数。
6 7 1 2 2 3 3 5 2 4 4 1 2 6 6 5 10 12 8 16 1 5 1 4 4 3 5 6
47
对于50%的数据,保证N,M≤3000。
对于100%的数据保证N,M≤5×105,0≤ai≤4000。
保证可以从市中心沿着 Siruseri 的单向的道路到达其中的至少一个酒吧。
首先利用tarjan缩点,将点权当作边权再建有权边,跑一边spfa最长路(板子很重要,考试的时候都忘了)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=5e5+10; 4 int n,m,cnt,top; 5 int u[N],v[N],val[N]; 6 int bar[N],Time; 7 int sta[N]; 8 bool vis[N]; 9 int dis[N]; 10 int s,p,head[N]; 11 int dfn[N],low[N]; 12 int tot,sum[N],g[N]; 13 queue<int>q; 14 struct edge{//两次建边结构体 15 int to; 16 int ne; 17 int w; 18 }e[N]; 19 20 void clear(){//清空函数 21 cnt=0; 22 memset(e,0,sizeof(e));//前楼大佬说结构体也能memset,但得保证类型都一样啊!! 23 memset(head,0,sizeof(head)); 24 } 25 26 void add(int u,int v){//第一次建边 27 e[++cnt].to=v; 28 e[cnt].ne=head[u]; 29 head[u]=cnt; 30 } 31 32 void build(int u,int v,int w){//第二次建边 33 e[++cnt].to=v; 34 e[cnt].ne=head[u]; 35 e[cnt].w=w; 36 head[u]=cnt; 37 } 38 39 void read(){//读入 40 scanf("%d%d",&n,&m); 41 for(int i=1;i<=m;i++){ 42 scanf("%d%d",&u[i],&v[i]); 43 add(u[i],v[i]); 44 } 45 for(int i=1;i<=n;i++){ 46 scanf("%d",&val[i]); 47 } 48 scanf("%d%d",&s,&p); 49 for(int i=1;i<=p;i++){ 50 scanf("%d",&bar[i]); 51 } 52 } 53 54 void tarjan(int u){//tarjan板子(板子狠重要呀) 55 dfn[u]=low[u]=++Time; 56 vis[u]=1; 57 sta[++top]=u; 58 for(int i=head[u];i;i=e[i].ne){ 59 int next=e[i].to; 60 if(!dfn[next]){ 61 tarjan(next); 62 low[u]=min(low[u],low[next]); 63 } 64 if(vis[next]){ 65 low[u]=min(low[u],dfn[next]); 66 } 67 } 68 if(dfn[u]==low[u]){//缩点 69 tot++; 70 while(sta[top+1]!=u){ 71 int tp=sta[top--]; 72 sum[tot]+=val[tp]; 73 vis[tp]=0; 74 g[tp]=tot; 75 } 76 //top--; 77 } 78 } 79 80 void spfa(int s){//spfa最长路 81 for(int i=1;i<=tot;i++)dis[i]=0; 82 int gs=g[s]; 83 q.push(gs); 84 vis[gs]=1; 85 dis[gs]=sum[gs]; 86 while(!q.empty()){ 87 int f=q.front(); 88 q.pop(); 89 vis[f]=0; 90 for(int i=head[f];i;i=e[i].ne){ 91 int next=e[i].to; 92 if(dis[next]<dis[f]+e[i].w){//符号改成>就是最短路了呀 93 dis[next]=dis[f]+e[i].w; 94 if(!vis[next]){ 95 q.push(next); 96 vis[next]=1; 97 } 98 } 99 } 100 } 101 } 102 103 int main(){ 104 read(); 105 for(int i=1;i<=n;i++){ 106 if(!dfn[i])tarjan(i); 107 } 108 clear(); 109 for(int i=1;i<=m;i++){ 110 if(g[u[i]]!=g[v[i]]){ 111 build(g[u[i]],g[v[i]],sum[g[v[i]]]); 112 } 113 } 114 spfa(s); 115 int ans=-10; 116 for(int i=1;i<=p;i++){ 117 ans=max(ans,dis[g[bar[i]]]);//枚举酒吧节点 118 } 119 printf("%d",ans); 120 return 0; 121 }
//完结撒花
小张最近发表了一篇论文,有一个神秘人物要给小张学院发奖学金。
小张学院有 c名学生,第 iii 名学生的成绩为 ai,要获得的奖学金金额为 bi。
要从这c名学生中挑出n名学生发奖学金。这个神秘人物爱好奇特,他希望得到奖学金的同学的成绩的中位数尽可能大,但同时,他们的奖学金总额不能超过 f。
第一行有三个整数,分别表示要挑出的学生人数n,学生总数c和奖学金总额的最大值f.
第二到(c+1)行,每行两个整数,第(i+1)行的整数依次表示第i名学生的成绩ai和要给他发的奖学金金额数bi。
输出一行一个整数表示答案。如果无法满足神秘人的条件,请输出 −1。
3 5 70 30 25 50 21 20 20 5 18 35 30
35
1 #include<bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 const int N=2e5+10;
5 ll F;
6 int n,c;
7 ll f[N],g[N];
8 struct Node{
9 ll cj;//成绩
10 ll m;//奖金
11 }e[N];
12
13 bool cmp(Node a,Node b){
14 return a.cj<b.cj;//按找成绩排序
15 }
16 ll sum;
17 priority_queue<int>q;//大根堆
18
19 int main(){
20 scanf("%d%d%lld",&n,&c,&F);
21 for(int i=1;i<=c;i++){
22 scanf("%lld%lld",&e[i].cj,&e[i].m);
23 }
24 sort(e+1,e+1+c,cmp);
25 for(int i=1;i<=n/2;i++){//成绩前n/2的人入队
26 sum+=e[i].m;//sum记录前二分之i个里的奖金数。大根堆放入。
27 q.push(e[i].m);
28 }
29 for(int i=n/2+1;i<=c;i++){//f[i]:表示以i为中位数前n/2人的最小奖金
30 f[i]=sum;
31 ll top = q.top();
32 if(top>e[i].m){//奖金小于堆顶则换掉,因为越小越好。
33 q.pop();
34 sum-=top;
35 sum+=e[i].m;
36 q.push(e[i].m);
37 }
38 }
39 sum=0;
40 while(!q.empty())q.pop();
41 for(int i=c;i>=c-(n/2)+1;i--){//成绩后n/2入队
42 sum+=e[i].m;
43 q.push(e[i].m);
44 }
45 for(int i=c-(n/2);i>=1;i--){//g[i]是i为中位数是后n/2人最小奖金
46 g[i]=sum;
47 ll top = q.top();
48 if(top>e[i].m){//同上,如果小,就换
49 q.pop();
50 sum-=top;
51 sum+=e[i].m;
52 q.push(e[i].m);
53 }
54 }
55 for(int i=c-n/2;i>=n/2+1;i--){//枚举每一种中位数的可能
56 if(f[i]+g[i]+e[i].m<=F){//因为是从大到小枚举的,所以满足情况就直接输出结束。
57 printf("%lld",e[i].cj);
58 return 0;
59 }
60 }
61 printf("-1\n");//没有合法情况就输出-1
62 return 0;
63 }
标签:胜利 over hang def 优化 queue org 没有 例子
原文地址:https://www.cnblogs.com/LightyaChoo/p/13204285.html