PS 过的人太多的就不贴代码了(当然过的人很少的我也不会QAQ,有的题如果能够补过的话,还会更新)
D 三体——人类的末日之战
分析:很明显的 bfs+状态压缩
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 200+11;
const int M = 1e6+11;
int to[4][2]={1,0,-1,0,0,1,0,-1};
int mp[N][N]; int n,m;
bool vis[N][N][1<<9];
struct Node{
int x,y,state,step;
};
int cnt;
void bfs(Node st){
queue<Node>que;
memset(vis,0,sizeof(vis));
vis[st.x][st.y][st.state]=1;
que.push(st);
while(!que.empty()){
Node now=que.front(); que.pop();
for(int i=0;i<4;i++){
int nx=now.x+to[i][0]; int ny=now.y+to[i][1];
if(nx<=0||nx>n ||ny<=0||ny>m) continue;
if(now.state == (1<<cnt)-1 ) {
printf("%d\n",now.step);
return ;
}
if(mp[nx][ny]>=1 && mp[nx][ny]<=cnt) {
if(vis[nx][ny][now.state]) continue;
vis[nx][ny][now.state]=1;
Node ne={nx,ny,now.state|(1<<(mp[nx][ny]-1)),now.step+1};
que.push(ne);
continue;
}
if(vis[nx][ny][now.state]) continue;
vis[nx][ny][now.state]=1;
Node ne={nx,ny,now.state,now.step+1};
que.push(ne);
}
}
}
int main(){
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m); string s;
Node st;
cnt=0;
for(int i=1;i<=n;i++){
cin>>s;
for(int j=0;j<m;j++){
if(s[j]=='W') {
mp[i][j+1]=0;
st.x=i; st.y=j+1; st.state=0; st.step=0;
}else if(s[j]=='S') {
mp[i][j+1]=++cnt;
}else if(s[j]=='#') {
mp[i][j+1]=0;
}
}
}
/*
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
printf("%d",mp[i][j]);
puts("");
}*/
bfs(st);
}
return 0;
}
E 豆落谁家
分析:dfs 暴力 ,收敛的很快
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
typedef pair<int,int>pii;
const int N = 1e5+11;
const int M = 1e6+11;
double cnt,p;
void dfs(int num,double gai,int a,int b){
if(num>50) return ;
if(b==0) p+=gai;
if(a==0 || b==0){
cnt+=num*gai;
return ;
}
int mn=min(a,b);
dfs(num+1,gai*0.5,a-mn,b+mn);
dfs(num+1,gai*0.5,a+mn,b-mn);
}
int main(){
int T ;scanf("%d",&T); int cas=1;
while(T--){
int n,m;
scanf("%d%d",&m,&n);
cnt=p=0;
dfs(0,1,m,n);
printf("Case %d:%.6lf %.6lf\n",cas++,cnt,p);
}
return 0;
}
问题 G: 战争联盟
分析: 带权并查集
我们维护 每个节点到根节点的距离 ,这样的话在同一个树上的两个点,如果他们到根节点的距离都是奇数或者都是偶数,那么肯定是同一个联盟,反之不是。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
typedef pair<int,int>pii;
const int N = 2e5+11;
const int M = 1e6+11;
const int inf = 0x3f3f3f3f;
int pre[N],relation[N];
void init(int n){
for(int i=0;i<=n;i++){
pre[i]=i;
relation[i]=0;
}
}
int Find(int x){
if(x==pre[x]) return x;
int t=pre[x];
pre[x]=Find(pre[x]);
relation[x]= relation[x]+relation[t]; // 路径压缩
return pre[x];
}
void Join(int x,int y){
int tx=Find(x); int ty=Find(y);
if(tx!=ty){
relation[tx]=relation[y]+1-relation[x];
pre[tx]=ty;
}
}
int main(){
int t;scanf("%d",&t);
while(t--){
int n,k; scanf("%d%d",&n,&k);
init(n);
while(k--){
char s[2];int a,b; scanf("%s %d %d",s,&a,&b);
if(s[0]=='A'){
if(Find(a)==Find(b)) {
if( (relation[a]+relation[b]) &1) puts("Belong to different group.");
else puts("Belong to same group.");
}else puts("Not sure yet.");
}else Join(a,b);
}
}
return 0;
}
H 贴瓷砖
分析:暴力就好(不过要提前预处理 每一行和每一列的前缀和)
时间复杂度o(n*n*n)
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 300+11;
int mp[N][N];
int row[N][N];
int vol[N][N];
LL ans[N];
int main(){
int n;
while(cin>>n){
if(!n) break;
memset(row,0,sizeof(row));
memset(vol,0,sizeof(vol));
memset(ans,0,sizeof(ans));
memset(mp,0,sizeof(mp));
for(int i=1;i<=n;i++){
getchar();
for(int j=1;j<=n;j++){
char zz;
scanf("%c",&zz);
mp[i][j]=zz-'0';
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
row[i][j]=row[i][j-1]+mp[i][j];
vol[i][j]=vol[i-1][j]+mp[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(mp[i][j]==0) continue;
for(int k=2;k<=n;k++){
int z=j+k-1; if(z>n) break;
if(row[i][z]-row[i][j-1] == k) {
int zz=i+k-1; if(zz>n) break;
if(vol[zz][j]-vol[i-1][j]==k) {
if(vol[zz][z]-vol[i-1][z] == k) {
if(row[zz][z]-row[zz][j-1] == k) {
ans[k]++;
}else break;
}else break;
}else break;
}else break;
}
}
}
for(int i=2;i<=n;i++){
if(ans[i]==0) continue;
printf("%d %lld\n",i,ans[i]);
}
puts("");
}
return 0;
}
J 飓风营救小灰灰
分析:直接BFS模拟就好
#include<bits/stdc++.h>
using namespace std;
#define LL long long
typedef pair<int,int>pii;
const int N = 100+11;
const int M = 1e6+11;
int to[4][2]={1,0,-1,0,0,1,0,-1};
int mp[N][N]; int n,m,c;
bool vis[N][N];
vector<pii>ve[10];
struct Node{
int x,y ,step;
};
void bfs(Node st){
queue<Node>que;
memset(vis,0,sizeof(vis));
que.push(st);
while(!que.empty()){
Node now=que.front();que.pop();
for(int i=0;i<4;i++){
int nx=now.x+to[i][0]; int ny=now.y+to[i][1];
if(nx<=0||nx>n||ny<=0||ny>m) continue;
if(mp[nx][ny]==12) continue;
if(vis[nx][ny]) continue;
if(mp[nx][ny]==10) {
printf("%d\n",now.step+1+1);
return ;
}
if(mp[nx][ny]>=0 && mp[nx][ny]<=c){
int v=mp[nx][ny];
for(int j=0;j<ve[v].size();j++){
pii p=ve[v][j];
if( p.first==nx && p.second==ny) continue;
Node ne={p.first,p.second,now.step+1};
que.push(ne);
}
vis[nx][ny]=1;
}
Node ne={nx,ny,now.step+1};
vis[nx][ny]=1;
que.push(ne);
}
}
puts("Trapped!");
}
int main(){
while(scanf("%d%d%d",&m,&n,&c)) {
for(int i=0;i<10;i++) ve[i].clear();
if(n==m&&n==c&&n==0) break;
string s;
Node st,ed;
for(int i=1;i<=n;i++){
cin>>s;
for(int j=0;j<m;j++){
if(s[j]=='S') {
mp[i][j+1]=11;
st.x=i; st.y=j+1; st.step=0;
}else if(s[j]=='E'){
ed.x=i; ed.y=j+1;ed.step=0;
mp[i][j+1]=10;
}else if(s[j]=='#' || s[j]=='M') {
mp[i][j+1]=12;
} else if(s[j]=='*') mp[i][j+1]=11;
else {
mp[i][j+1]=s[j]-'0';
int val=s[j]-'0';
ve[val].push_back(make_pair(i,j+1)) ;
}
}
}
/*
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
printf("%d ",mp[i][j]);
puts("");
}
*/
bfs(st);
}
return 0;
}
K 数字拼图
分析:百度直接搜 拼图游戏 很多解释的。
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 10+11;
const int M = 1e6+11;
const int inf = 0x3f3f3f3f;
int a[N*N],sz;
int main(){
int n;
while(cin>>n){
if(!n) break;
sz=0;int Pb=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int zz; cin>>zz;
if(zz==0){
a[sz++]=inf;
Pb+=i+j;
}
else a[sz++]=zz;
}
}
int Pa=n+n;
for(int i=0;i<sz;i++){
for(int j=0;j<i;j++) {
if(a[j]>a[i]) Pb++;
}
}
if((Pb+Pa)&1) puts("NO"); // 原图和目标图的 奇偶一定要相同
else puts("YES");
}
return 0;
}
L Fehead的项目
分析: 对于任意一个区间来说,其面积为 区间中最小值*区间长度,所以直接建立一颗线段树维护就ok了
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
typedef pair<int,int>pii;
const int N = 100000+11;
const int M = 1e6+11;
const int inf = 0x3f3f3f3f;
struct Tree{
int le,ri,len;
LL mn,mx;
}tree[N<<2];
void Up(int o){
tree[o].mn=min(tree[o<<1].mn,tree[o<<1|1].mn);
tree[o].mx=max(tree[o<<1].mx,tree[o<<1|1].mx);
tree[o].mx=max(tree[o].mx,tree[o].len*tree[o].mn);
}
void Build(int o,int le,int ri){
tree[o].le=le;tree[o].ri=ri; tree[o].len=ri-le+1;
if(le==ri){
LL val;
scanf("%lld",&val);
tree[o].mn=tree[o].mx=val;
return ;
}
int mid=(le+ri)>>1;
Build(o<<1,le,mid);
Build(o<<1|1,mid+1,ri);
Up(o);
}
int main(){
int n;
while(scanf("%d",&n)!=EOF && n){
Build(1,1,n);
printf("%lld\n",tree[1].mx);
}
return 0;
}
S 躁动的小Z
分析:求最短路的同时直接维护一下前驱就行了。
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
#define LL long long
const int N = 1e5+11;
const int M = 1e6;
const int mod = 7653;
const int inf = 0x3f3f3f3f;
const double E = exp(1.0);
struct Edge{
int from,to,val,next;
}edge[M];
int head[N],top;
void init(){
memset(head,-1,sizeof(head));
top=0;
}
void addedge(int a,int b,int c){
Edge e={a,b,c,head[a]};
edge[top]=e; head[a]=top++;
}
int dis[N]; bool vis[N];
int pre[N];
void spfa(int st){
queue<int>Q;
memset(dis,inf,sizeof(dis));
memset(vis,false,sizeof(vis));
memset(pre,-1,sizeof(pre));
Q.push(st); vis[st]=true; dis[st]=0;
while(!Q.empty()){
int now=Q.front();Q.pop();vis[now]=false;
for(int i=head[now];i!=-1;i=edge[i].next){
Edge e=edge[i];
if(dis[e.to]>dis[now]+e.val){
dis[e.to]=dis[now]+e.val;
pre[e.to]=now;
if(!vis[e.to]){
vis[e.to]=true;
Q.push(e.to);
}
}
}
}
}
int have;
void OutPut(int now){
if(now==-1) return ;
OutPut(pre[now]);
if(have++) putchar(' ');
printf("%d",now);
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
init();
for(int i=1;i<=m;i++){
int a,b,c;scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
addedge(b,a,c);
}
spfa(1);
// for(int i=1;i<=n;i++) printf("%d ",pre[i]);
if(dis[n]>=inf) puts("-1");
else {
have=0;
OutPut(n);
puts("");
}
}
return 0;
}