解题思路

简要记录题解思路

f:battle City

bfs+优先队列

每次入队前进行标记,每次出队都上当前最短的路径
bfs+优先队列似乎就是dijkstra算法 ??

code

char mp[maxm][maxn];
int vis[maxm][maxn];//记录是否处理过
struct node{
    int x,y;
    int step;
    node(int x_,int y_,int s_):x(x_),y(y_),step(s_){}
};
 bool operator < (node a,node b){
        return a.step>b.step;
    }
int mv[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
//优先队列

int m,n;
int bfs(node begin,int endx,int endy){
    priority_queue<node> que;
    vis[begin.x][begin.y]=1;
    que.push(begin);
    while(!que.empty()){
        node tmp=que.top();
        que.pop();
        //printf("db %d %d step %d
",tmp.x,tmp.y,tmp.step);
        if(tmp.x==endx&&tmp.y==endy) return tmp.step;
        int tmpx,tmpy,tmps;
        for(int i=0;i<4;i++){
            tmpx=tmp.x+mv[i][0];
            tmpy=tmp.y+mv[i][1];
            if(tmpx<0||tmpx>=m||tmpy<0||tmpy>=n||vis[tmpx][tmpy]||mp[tmpx][tmpy]=='S'||mp[tmpx][tmpy]=='R') continue;//依旧可能出现相同坐标都在队列中
            else if(mp[tmpx][tmpy]=='B') tmps=tmp.step+2;
            else tmps=tmp.step+1;
            node t=node(tmpx,tmpy,tmps);
            vis[tmpx][tmpy]=1;
            que.push(t);
            //else if(mp[tmpx][tmpy]=='B'){node t=node(tmpx,tmpy,tmp.step+2);vis[tmpx][tmpy]=1;que.push(t);}
            //else if(mp[tmpx][tmpy]=='E'||mp[tmpx][tmpy]=='T'){node t=node(tmpx,tmpy,tmp.step+1);vis[tmpx][tmpy]=1;que.push(t);}

        }
    }
    return -1;//no find
}
node beg=node(0,0,0);
int endx,endy;
int main(){
    while(scanf("%d %d",&m,&n)&&m!=0){
        //CL(mp,0);
        CL(vis,0);
        /*
        while(!que.empty()){
            que.pop();
        }
        */
        for(int i=0;i<m;i++){
            scanf("%s",mp[i]);
            for(int j=0;j<n;j++){
                if(mp[i][j]=='Y'){
                    beg.x=i,beg.y=j,beg.step=0;
                }
                if(mp[i][j]=='T'){
                    endx=i,endy=j;
                }
            }
        }
        int ans=bfs(beg,endx,endy);
        printf("%d
",ans);
    }
    return 0;
}

g: 从N个数里找出和为N的倍数

数学题(鸽巢原理)+前缀和

处理前缀和的模N为0和相同的情况

code

void output(int i,int j){
    printf("%d
",j-i);
    for(int t=i+1;t<=j;t++){
        printf("%d
",a[t]);
    }
}
int main(){
    scanf("%d",&n);
        //CL(tag,-1);
        bool flag=false;//是否已经找到该组数据答案
        for(int i=1;i<=n;i++){
            scanf("%d",a+i);
            if(flag) continue;
            sum[i]=a[i];
            sum[i]+=sum[i-1];
            int mod=sum[i]%n;
            if(mod==0){
                output(0,i);
                flag=true;
                continue;
            }
            //printf("db %d %d mod %d tag[mod] %d
",i,sum[i],mod,tag[mod]);
            if(tag[mod]==0){
                tag[mod]=i;
            }
            else{
                output(tag[mod],i);
                flag=true;
            }
        }

    
    return 0;
}

h :判断负环

bellman-ford

bellman-ford算法处理单源最短路(可以有负边),基本操作:
N-1次的松弛,每次松弛时对边<u,v> dis[v]=min(dis[v],dis[u]+cost(u,v))
不优化的复杂度O(NE)

code

struct Edge{
    int u,v,w,next;
    //Edge(int u_,int v_,int w_):u(u_),v(v_),w(w_) {}
}es[maxm];//maybe be not need u
int head[maxn];//head[u]链表头,边编号
int dis[maxn];
//init -1
int cnt;
void add(int u,int v,int w){
    es[cnt].u=u;es[cnt].v=v;es[cnt].w=w;
    es[cnt].next=head[u];
    head[u]=cnt;
    cnt++;
}
void bellman(int s){
    //原点s进行bellmanford算法
    CL(dis,0x3f);
    dis[s]=0;// dis0
    //dis1...dis(n-1)
    //dis(n)[j]=min(dis(n-1)[j],dis(n-1)[i]+cost[i][j])
    for(int t=1;t<=n-1;t++){
        //优化之一如果有一次都没更新则停止
        //便利所有边
        for(int j=0;j<cnt;j++){
            int u=es[j].u;
            int v=es[j].v;
            int w=es[j].w;
            if(dis[v]>dis[u]+w) dis[v]=dis[u]+w;//更新
        }

    }
}
bool check(){
    //n-1次后还能更新则存在负环
    for(int j=0;j<cnt;j++){
    int u=es[j].u;
    int v=es[j].v;
    int w=es[j].w;
    if(dis[v]>dis[u]+w) return false;
    }
    return true;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d %d %d",&n,&m,&W);
        //初始化
        cnt=0;
        CL(head,-1);
        int u,v,w;
        
        for(int i=0;i<m;i++){
            scanf("%d %d %d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
        }
        for(int j=0;j<W;j++){
            scanf("%d %d %d",&u,&v,&w);
            w=0-w;
            add(u,v,w);
        }
        //printf("cnt %d
",cnt);
        bool tag=false;
        //for(int i=1;i<=n;i++){//如果每个点都操作,不知道为什么回WA 而不是TLE,总之是很怪的题目
            bellman(1);
            if(!check()){
                //printf("YES
");
                tag=true;
                //break;
            }
        //}
        if(tag) printf("YES
");
        else printf("NO
");   

    }
    return 0;
}

I:正方形(找出N个整点构成的正方形个数)

手写hash+简单几何关系

枚举两点,得到正方形的另外两点,hash检索(注意选模,搜索时时搜索自由区域才停)
注意枚举重复情况(4条边都被枚举遍)

code

const int maxn=100007;
struct point{
    int x,y;
    int count;//标志有效位置
}hash[100007];
int n;
int xx[1005],yy[1005];
void tohash(int x,int y){
    int pos=(x*x+y*y+x-y)%maxn;
    while(hash[pos].count!=0){
        pos=(pos+1)%maxn;
    }
    hash[pos].count=1;
    hash[pos].x=x;hash[pos].y=y;


}
int search(int x,int y){
    int pos=(x*x+y*y+x-y)%maxn;
    while(hash[pos].count!=0){
        if(hash[pos].x==x&&hash[pos].y==y) return 1;
        pos=(pos+1)%maxn;
    }
    //printf("db search pos:%d x %d y %d
",pos,x,y);
    //if(hash[pos].x==x&&hash[pos].y==y) return 1;
    return 0;
}

int main(){
    while(scanf("%d",&n)&&n!=0){
        CL(hash,0);
        int x,y;
        for(int i=0;i<n;i++){
            scanf("%d %d",&x,&y);
            xx[i]=x,yy[i]=y;
            tohash(x,y);
        }
        int ans=0;
        //for(int i=0;i<=4;i++){
            //printf("db i:%d %d %d %d
",i,hash[i].x,hash[i].y,hash[i].count);
        //}
        //printf("db %d %d
",search(0,0),search(0,1));
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                if(i==j) continue;
                int x1=xx[i],x2=xx[j],y1=yy[i],y2=yy[j];
                int dx=x2-x1,dy=y1-y2;
                //(x1+dy,y1+dx) (x2+dy,y2+dx)
                //(x1-dy,y1-dx) (x2-dy,y2-dx)
                //printf("i:%d j:%d searchpoint1 %d %d %d %d piint2 %d %d %d %d
",i,j,x1+dy,y1+dx,x2+dy,y2+dx,x1-dy,y1-dx,x2-dy,y2-dx);
                ans+=(search(x1+dy,y1+dx)&search(x2+dy,y2+dx));
                ans+=(search(x1-dy,y1-dx)&search(x2-dy,y2-dx));
                //printf("db ans %d
",ans);
            }
            
        }
        printf("%d
",ans>>2);

    }
    return 0;

}

j:container

给出三维整点左边,要将这些区域包裹起来的最小表面积

6n-2m ;n是点的个数,m是相接的面
但没找到原题,无法测试

code

struct cell{
    int x,y,z;
}cels[maxn];
int n;
bool checkadj(cell c1,cell c2){
    return (abs(c1.x-c1.x)+abs(c1.y-c2.y)+abs(c1.z-c2.z))<=1;//no same
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%d %d %d",&cels[i].x,&cels[i].y,&cels[i].z);
        }
        int ans=6*n;
        for(int i=1;i<n;i++){
            for(int j=0;j<i;j++){
                if(checkadj(cels[i],cels[j])) ans-=2;
            }
        }
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/fridayfang/p/10420935.html