寒假洛谷刷题技巧(1)

越来越不想写博客了。。。。但适当总结是很必要的。
1.深搜和广搜当有多组样例时,注意全局变量的清0和更新,还有数组和标记数组都要清0!!
2.数组标记用了不会错,不用可能超时,尽量都用。
3.一种通过递归记录路径的方法真实太妙了!!虽然我用的广搜的模板,但这个记录路径的方法有深搜的影子,很妙。
https://www.luogu.com.cn/problem/P6207

#include 

using namespace std;
struct node
{
    int x,y,s;
};
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int r,c,vis[200][200],dist[200][200][2],k;
char a[200][200];
queue<node>q;
void bfs()
{
    vis[1][1]=1;
    node cur,nxt;
    cur.x=1;cur.y=1;cur.s=0;
    q.push(cur);
    while(!q.empty())
    {
        cur=q.front();q.pop();
        if(cur.x==r&&cur.y==c)
            return ;
        for(int i=0;i<4;i++)
        {
            nxt.x=cur.x+dx[i];
            nxt.y=cur.y+dy[i];
            if(a[nxt.x][nxt.y]=='.'&&vis[nxt.x][nxt.y]==0&&nxt.x>=1&&nxt.x<=r&&nxt.y>=1&&nxt.y<=c)
            {
                nxt.s=cur.s+1;vis[nxt.x][nxt.y]=1;q.push(nxt);
                dist[nxt.x][nxt.y][0]=cur.x;
                dist[nxt.x][nxt.y][1]=cur.y;
            }
        }
    }
}
void print(int x,int y)
{
    if(!(dist[x][y][0]+dist[x][y][1])) return;
	print(dist[x][y][0],dist[x][y][1]);
	printf("%d %d\n",x,y);
}
int main()
{
    scanf("%d%d",&r,&c);
    for(int i=1;i<=r;i++)
        for(int j=1;j<=c;j++)
            cin>>a[i][j];
    bfs();
    puts("1 1");
    print(r,c);
    return 0;
}

4.用while构造不同进制,统计不同进制下的波浪数,卡了我好久,就是想不明白,虽然用到的思想知识构造,捎带一点进位转换。。。
https://www.luogu.com.cn/problem/P1112

#include 

using namespace std;
int a,b,c,d,k,f[50],q[10000005],sum,t;
void go(int x)
{
    for(int i=1;i<x;i++)
    {
        for(int j=0;j<x;j++)
        {
            if(i!=j)
            {
                sum=0;t=0;
                while(sum<=d)
                {
                    if(t%2==0)
                    {
                        sum=sum*x+i;t++;
                    }
                    else
                    {
                        sum=sum*x+j;t++;
                    }
                    if(sum>=c&&sum<=d)
                            q[sum]++;
                }
            }
        }
    }
}
int main()
{
    cin>>a>>b>>c>>d>>k;
    for(int i=a;i<=b;i++)
        go(i);
    for(int i=c;i<=d;i++)
    {
        if(q[i]==k)
            cout<<i<<endl;
    }
    return 0;
}

5.next_permutation 函数的使用,列出全排列,基本代码格式:

int main() {
	string str;  //字符串的全排列
	cin>>str;
	sort(str.begin(),str.end());
	do{
		cout<<str<<endl;
	}while(next_permutation(str.begin(),str.end()));
	return 0;
}

6.杨辉三角的参数计算,这种深搜到的方式掌握的并不好
https://www.luogu.com.cn/problem/P1118

#include 

using namespace std;
int pc[50],n;
int main()
{
    cin>>n; //输入n,算的是C(0到n-1,n-1)的排列
    pc[0]=pc[n-1]=1;
    if (n>1)
        for (int i=1;i*2<n;i++)
            pc[i]=pc[n-1-i]=(n-i)*pc[i-1]/i;//杨辉三角的对称性
    for(int i=0;i<n;i++)
        cout<<pc[i]<<" ";
    cout<<endl;
    return 0;
}
#include 

using namespace std;
int pc[50],n,k,vis[50],ans[50],sum;
int dfs(int i,int num,int sum) //枚举第i个数,第i个数是什么,当前和sum
{
    if(sum>k) return 0;
    if(i==n)
    {
        if(sum==k)
        {
            ans[i]=num;return 1;
        }
        else return 0;
    }
    vis[num]=1;
    for(int j=1;j<=n;j++)
    {
        if(!vis[j]&&dfs(i+1,j,sum+pc[i]*j))
        {
            ans[i]=num;return 1;
        }
    }
    vis[num]=0;
    return 0;
}
int main()
{
    cin>>n>>k; //输入n,算的是C(0到n-1,n-1)的排列
    pc[0]=pc[n-1]=1;
    if (n>1)
        for (int i=1;i*2<n;i++)
            pc[i]=pc[n-1-i]=(n-i)*pc[i-1]/i;//杨辉三角的对称性
    if(dfs(0,0,0))
        for(int i=1;i<=n;i++)
            cout<<ans[i]<<" ";
    cout<<endl;
    return 0;
}

7.学到一种新的找最长回文字符串的方式。遍历每个字符,通过长度的奇偶比较返回大的那个值。本题从格式处理上增加了难度。

#include 

using namespace std;
const int maxn=20005;
char s[maxn],s1[maxn];
int pos[maxn],n,l,t,mn1,ls;
int check(int x)
{
    int a1=1,a2=0;
    for(int i=x,j=1;i-j>=0&&i+j<l&&s1[i-j]==s1[i+j];j++)  //奇数从1开始
        a1+=2;
    for(int i=x,j=0;i-j>=0&&i+j+1<l&&s1[i-j]==s1[i+j+1];j++) //偶数从0开始
        a2+=2;
    return max(a1,a2);
}
int main()
{
    while((s[n]=getchar())!=EOF) n++;
    for(int i=0;i<n;i++)
    {
        if(isalpha(s[i]))
        {
            s1[l]=tolower(s[i]);
            pos[l++]=i; //提取的字符所在位置
        }
    }
    for(int i=0;i<l;i++)
    {
        t=check(i);
        if(t>mn1)
        {
            mn1=t;
            ls=i+(t/2);
        }
    }
    s[pos[ls]+1]='\0';
    printf("%d\n%s\n",mn1,&s[pos[ls-mn1+1]]);
    return 0;
}

8.并查集的题目,算作复习一下,用结构体存一直通不过,改为数组存数据就通过了。
啊啊啊啊啊,是我的代码出问题了,有时因为一个下标写错检查半天,我还怀疑是结构体的存储方式出问题了。。。。。我想一头撞死
https://www.luogu.com.cn/problem/P3144

#include 
using namespace std;
struct node
{
    int l,r;
}e[3005];
int f[3005],n,m,ans,p[3005],q[3005];

int r_find(int r)
{
    while(r!=f[r]) r=f[r];
    return r;
}
void init()
{
    for(int i=1;i<=n;i++)
        f[i]=i;
    return;
}
void mg(int x,int y)
{
    int fx,fy;
    fx=r_find(x);fy=r_find(y);
    if(fx!=fy)
        f[fx]=fy;
}
int check()
{
    int k=0;
    for(int i=1;i<=n;i++)
    {
        if(q[i]==1) continue;
        if(f[i]==i) k++;
    }
    if(k>=2) return 0;
    else
    return 1;
}
int main()
{
    scanf("%d%d",&n,&m);
    init();
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&e[i].l,&e[i].r);
        mg(e[i].l,e[i].r);
    }
    int k=0;
    for(int i=1;i<=n;i++)
    {
        if(f[i]==i)
            k++;
    }
    if(k>=2)
        ans=1;
    for(int i=1;i<=n;i++)
    {
        if(ans==1&&i==1)
        {
            printf("NO\n");
            continue;
        }
        init();
        scanf("%d",&p[i]);
        q[p[i-1]]=1; //此农场已关闭

        for(int j=1;j<=m;j++)
        {
            if(q[e[j].l]==0&&q[e[j].r]==0)
                mg(e[j].l,e[j].r);
        }
        if(check())
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
    return 0;
}

9.本题是最长路径,相对于一点到一点的最短路径,优先广度搜索,是一道裸题。
https://www.luogu.com.cn/problem/P1807

#include 

using namespace std;
int n,m,edge[5000][5000],f[2000],x,y,z,sum,ans;
queue<int>q;
void bfs()
{
    memset(f,-1,sizeof(f));
    f[1]=0;    //f[i]记录到结点i的最长路
    q.push(1); //存放到的点
    while(!q.empty())
    {
        int cur=q.front();
        q.pop();
        for(int i=1;i<=n;i++)
        {
            if(edge[cur][i]>0&&f[i]<f[cur]+edge[cur][i])  
            {
                f[i]=f[cur]+edge[cur][i];  //使用max函数反而会超时,因为程序多次进入if语句,被压入队列中
                q.push(i);
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        edge[x][y]=max(edge[x][y],z);
    }
    bfs();
    cout<<f[n]<<endl;
    return 0;
}

10.一个动态迷宫问题。会不断有路障掉下来,本题是输出yes或no,还有一种思路是只考虑路障。
https://www.luogu.com.cn/problem/P3395

#include 

using namespace std;
struct node
{
    int x,y,t;
};
int mp[1005][1005],zx[2005],zy[2005],fg,n,ans;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
bool vis[1005][1005];
queue<node>q;
void bfs(int x,int y,int t)
{
    node cur,nxt;
    cur.x=x;cur.y=y;cur.t=t;
    q.push(cur);
    while(!q.empty())
    {
        cur=q.front();
        q.pop();
        int a,b,c;a=cur.x;b=cur.y;c=cur.t;
        if(a==n&&b==n)
        {
            fg=1;break;
        }
        mp[zx[c]][zy[c]]=1;
        for(int i=0;i<4;i++)
        {
            int xx=a+dx[i];int yy=b+dy[i];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=n&&vis[xx][yy]==0&&mp[xx][yy]==0)
            {
                nxt.x=xx;nxt.y=yy;nxt.t=c+1;
                vis[xx][yy]=1;
                q.push(nxt);
            }
        }
    }
}
int main()
{
    int t;scanf("%d",&t);
    while(t--)
    {
        memset(vis,0,sizeof(vis));
        memset(mp,0,sizeof(mp));
        fg=0;
        scanf("%d",&n);
        for(int i=1;i<=2*n-2;i++)
            scanf("%d%d",&zx[i],&zy[i]);
        vis[1][1]=1;
        bfs(1,1,0);
        if(fg)
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;
    }
    return 0;
}

你可能感兴趣的:(acm算法学习,算法,图论,动态规划)