2022-XTU程设练习3

两个题没写,被恶心到了,也许也是我太菜了,如果有疑问或者纠错,或者想告诉我某些我不会的题的思路。可以评论区发给我,我很乐意的,。。。另外我程设居然过了,感谢谢大手下留情......

1.逆序数(大数据)-1167

样例输入

3
3 1 2
4
1 2 3 4
0

样例输出

2
0

思路:只能归并排序和树状数组,这里我讲讲归并排序。

很好理解,只是自己还是不会敲出来,就是从中间开始分,同时排序左右两边,在左边基础上又分为左右两边,在右边的基础上又分为左右两边,将大的排序分为小的排序,排序完成然后全部整合。

在排序的过程中你会发现,左边还没来得及复制的T就是所以比a[j]大的数,所以加m-q即可。

Memory: 1516KTime: 234MS
#include <stdio.h>
#include <string.h>
using namespace std;
int a[10001];
int temp[10001];//中介,这个是排序后的结果
int res=0;
void MergeSort(int x,int y)
{
    if(y-x>1){
        int sum=0;
        int m=(x+y)/2;
        int p=x,q=m,i=x;
        MergeSort(x,m);
        MergeSort(m,y);
        while(p<m||q<y){
            if(q>=y||(p<m&&a[p]<=a[q])){
                temp[i++]=a[p++];
            }
            else{
                temp[i++]=a[q++];
                sum+=m-p;//x_______m_______y,p在x-m之间,q在m-y之间
            }
        }
        for(int i=x;i<y;i++){
            a[i]=temp[i];
        }
        res+=sum;
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    while(n!=0){
        res=0;
        memset(a,0,sizeof(a));
        memset(temp,0,sizeof(temp));
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
        }
        MergeSort(0,n);
        /*for(int i=0;i<n;i++){
            printf("%d ",a[i]);
        }*/
        printf("%d\n",res);
        scanf("%d",&n);
    }
    return 0;
}

2.1179-Shortest Path

样例输入

3 3 1 
1 2 3 
2 3 4 
1 3 2 
2 
0 0 0

样例输出

7

 思路:dijkstra算法。但是注意啊,有重边取最小,而且必须按顺序经过且只能经过一次,所以一开始就得有路径被标记成已经走过,举个栗子。

1----a1----a2----a3----n

从1开始必须终点是a1,所以,a2,a3,n它不能走。

a1的终点是a2,因此1,a3,n它不能走。

a2,1,a1,n不能走。

......

所以开始就标记已经走过即可。

Memory: 6120KTime: 1999MS
#include <stdio.h>
#include <queue>
#include <algorithm>
#include <string.h>
#include <limits.h>
typedef long long ll;
using namespace std;
int d[1101];
int vis[1101];
int s[1101][1101];
int n,m,k;
struct node
{
    int x,y;
    bool operator<(const node&b)const
    {
        return y>b.y;
    }
};
void djsrt(int t)
{
    fill(d,d+1101,INT_MAX/2);
    d[t]=0;
    priority_queue<node>q;
    node temp;
    temp.x=t,temp.y=0;
    q.push(temp);
    while(!q.empty()){
        node st=q.top();
        q.pop();
        if(vis[st.x]==1){
            continue;
        }
        vis[st.x]=1;
        int a=st.x;
        for(int i=0;i<n;i++){
            if(vis[i]==0&&s[a][i]<INT_MAX/2){
                if(d[i]>d[a]+s[a][i]){
                    d[i]=d[a]+s[a][i];
                    q.push((node){i,d[i]});
                }
            }
        }
    }
}
int main()
{
    //FILE *fpRead=fopen("D://huancun//1179//std.in","r");
    scanf("%d%d%d",&n,&m,&k);
    while(1){
        if(n==m&&m==k&&k==0){
            break;
        }
        int a[3];
        memset(a,0,sizeof(a));
        fill(s[0],s[0]+1101*1101,INT_MAX/2);
        for(int i=0;i<m;i++){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            if(s[a-1][b-1]>c){
                s[a-1][b-1]=c;
                s[b-1][a-1]=c;
            }
        }
        for(int i=0;i<k;i++){
            scanf("%d",&a[i]);
        }
        ll res=0;
        memset(vis,0,sizeof(vis));
        if(k==0){//暴力一点,看得更清楚
            djsrt(0);
            res+=d[n-1];
        }
        else if(k==1){
            vis[n-1]=1;//标记
            djsrt(0);
            res+=d[a[0]-1];
            memset(vis,0,sizeof(vis));
            vis[0]=1;
            djsrt(a[0]-1);
            res+=d[n-1];
        }
        else if(k==2){
            vis[n-1]=1;//标记
            vis[a[1]-1]=1;
            djsrt(0);
            res+=d[a[0]-1];
            memset(vis,0,sizeof(vis));
            vis[n-1]=1;
            vis[0]=1;
            djsrt(a[0]-1);
            res+=d[a[1]-1];
            memset(vis,0,sizeof(vis));
            vis[0]=1;
            vis[a[0]-1]=1;
            djsrt(a[1]-1);
            res+=d[n-1];
        }
        else if(k==3){
            vis[n-1]=1;//标记
            vis[a[1]-1]=1;
            vis[a[2]-1]=1;
            djsrt(0);
            res+=d[a[0]-1];
            memset(vis,0,sizeof(vis));
            vis[n-1]=1;
            vis[0]=1;
            vis[a[2]-1]=1;
            djsrt(a[0]-1);
            res+=d[a[1]-1];
            memset(vis,0,sizeof(vis));
            vis[n-1]=1;
            vis[0]=1;
            vis[a[0]-1]=1;
            djsrt(a[1]-1);
            res+=d[a[2]-1];
            memset(vis,0,sizeof(vis));
            vis[0]=1;
            vis[a[0]-1]=1;
            vis[a[1]-1]=1;
            djsrt(a[2]-1);
            res+=d[n-1];
        }
        if(res>=INT_MAX/2){
            printf("Impossible\n");
        }
        else{
            printf("%lld\n",res);
        }
        scanf("%d%d%d",&n,&m,&k);
    }
    return 0;
}

3.1195-Large Population

Sample Input

2 
2 1 
1 2 1 
3 3 
1 2 1 
1 3 2 
2 3 3

Sample Output

1
5

 思路:prim()算法,要求最大,我们只需要反过来把输入变成负数,因为prim求的是最小,这样求出来之后然后取反即可。注意重边,当时long好像不能用,所以只能用I64。

Memory: 9224KTime: 1343MS
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <limits.h>
using namespace std;
typedef long long ll;
__int64 matx[1011][1011];
__int64 visited[1011];
__int64 d[1011];
int n,m;
__int64 prim()
{
    fill(d,d+1010,INT_MAX);
    d[0]=0;
    __int64 res=0;
    for(int i=0;i<n;i++){
        __int64 mins=INT_MAX,id=0;
        for(int j=0;j<n;j++){
            if(visited[j]==0&&d[j]<mins){
                id=j;
                mins=d[j];
            }
        }
        //printf("%d ",id);
        visited[id]=1;
        res+=d[id];
        //printf("%lld\n",res);
        for(int k=0;k<n;k++){
            if(visited[k]==0&&matx[id][k]!=INT_MAX&&matx[id][k]<d[k]){
                d[k]=matx[id][k];
            }
        }
    }
    return res;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        memset(visited,0,sizeof(visited));
        fill(matx[0],matx[0]+1010*1010,INT_MAX);
        for(int i=0;i<m;i++){
            int a,b;
            __int64 c;
            scanf("%d%d%I64d",&a,&b,&c);
            if(matx[a-1][b-1]>-c){
                matx[a-1][b-1]=-c;
                matx[b-1][a-1]=-c;
            }

        }
        __int64 res=prim();
        printf("%I64d\n",-res);
    }
    return 0;
}

4.1245-Lisa's Puzzle

样例输入

5
5
13
1
2
3

样例输出

1
0
3
0
0

思路:这个题目很有意思,我们可以把它当做一个字典树,因为是二进制,所以是二叉字典树,树的每一个节点都可以表示一个数,这样后缀就可以直观看到了。

Memory: 26352KTime: 968MS
#include <stdio.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
ll b[100010]={0};
int main()
{
    unordered_map<ll,ll>a;
    int n;
    scanf("%d",&n);
    int t=0;
    while(n--){
        ll m;
        scanf("%lld",&m);
        b[t++]=m;
        ll ans=0;
        while(m!=0){
            if(m%2==1){
                ans=ans*2+2;
                a[ans]++;
            }
            else{
                ans=ans*2+1;
                a[ans]++;
            }
            m/=2;
        }
    }
    for(ll i=0;i<t;i++){
        ll ans=0;
        ll res=INT_MAX;
        while(b[i]!=0){
            if(b[i]%2==1){
                ans=ans*2+2;
                res=min(res,a[ans]);
            }
            else{
                ans=ans*2+1;
                res=min(res,a[ans]);
            }
            b[i]/=2;
        }
        printf("%lld\n",res-1);
    }
    return 0;
}

5.1250-Bonus

样例输入

2
3 2
1 2
2 3
3 2
1 2
2 1

样例输出

5664
2888 1888 888
2664
888 888 888

 思路:拓扑和bfs选一个即可,只是题意感觉不怎么明白。参考了别人的题解。

Memory: 4200KTime: 452MS
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
typedef long long ll;
vector<ll>res[10010];
ll s[10010],vis[10010];
ll dfs(ll nums)
{
    vis[nums]=-1;//正在访问
    for(ll i=0;i<res[nums].size();++i){
        ll id=res[nums][i];
        if(vis[id]<0){
            return -1;
        }
        if(vis[id]==0){
            s[id]=dfs(id);
        }
        if(s[id]<0){
            return -1;
        }
        if(s[nums]<s[id]+1000){
            s[nums]=s[id]+1000;
        }
    }
    vis[nums]=1;
    return s[nums];
}
ll ts(ll n)
{
    memset(vis,0,sizeof(vis));
    for(ll i=1;i<=n;i++){
        if(!vis[i]&&dfs(i)<0){
            return -1;
        }
    }
    return 0;
}
int main()
{
    ll t;
    scanf("%lld",&t);
    while(t--){
        ll n,m;
        scanf("%lld%lld",&n,&m);
        for(ll i=1;i<=n;i++){
            res[i].clear();
            s[i]=888;
        }
        for(ll i=0;i<m;i++){
            ll a,b;
            scanf("%lld%lld",&a,&b);
            res[a].push_back(b);
        }
        ll sum=0;
        if(ts(n)<0){
            sum=n*888;
            printf("%lld\n",sum);
            for(ll i=1;i<n;i++){
                printf("%lld ",888);
            }
            printf("888\n");
        }
        else{
            for(ll i=1;i<=n;i++){
                sum+=s[i];
            }
            printf("%lld\n",sum);
            for(ll i=1;i<n;i++){
                printf("%lld ",s[i]);
            }
            printf("%lld\n",s[n]);
        }
    }
    return 0;
}

6.1288-Binary Search Tree

样例输入

2
5 5
3 2 5 1 4
3 1 2 5 4
3 2 1 5 4
3 5 2 1 4
3 5 4 2 1
3 2 4 5 1
3 2
1 2 3
1 3 2
3 2 1

样例输出

1: No
2: Yes
3: Yes
4: Yes
5: No

1: No
2: No

 思路:中+前/后序遍历绝对一棵树 ,所以最直观的方法就是前序或者后续遍历即可,还能优化一下,但是能过已经够了。

Memory: 63808KTime: 1734MS
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
int ch[1001],flag=0,ans=0;
struct Treenode
{
    int val;
    Treenode *l;
    Treenode *r;
};
Treenode* create(Treenode* t)//二叉树模板
{
    t=new Treenode;
    t->l=nullptr;
    t->r=nullptr;
    return t;
}
Treenode* into(Treenode* t,int val)
{
    if(t==nullptr){
        t=create(t);
        t->val=val;
        return t;
    }
    if(val<t->val){
        t->l=into(t->l,val);
        return t;
    }
    if(val>t->val){
        t->r=into(t->r,val);
        return t;
    }
}
void pre(Treenode* t)//前序
{
    if(t==nullptr){
        return;
    }
    ch[ans++]=t->val;
    pre(t->l);
    pre(t->r);
}
void pres(Treenode* t)//前序
{
    if(t==nullptr){
        return;
    }
    if(ch[ans++]!=t->val){
        flag=1;
        return;
    }
    pres(t->l);
    pres(t->r);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m;
        flag=0,ans=0;
        scanf("%d%d",&n,&m);
        memset(ch,0,sizeof(ch));
        Treenode *root=nullptr;
        for(int i=0;i<n;i++){
            int nums;
            scanf("%d",&nums);
            root=into(root,nums);
        }
        pre(root);
        for(int i=0;i<m;i++){
            flag=0;
            ans=0;
            Treenode *t=nullptr;
            for(int j=0;j<n;j++){
                int nums;
                scanf("%d",&nums);
                t=into(t,nums);
            }
            pres(t);
            if(flag==0){
                printf("%d: Yes\n",i+1);
            }
            else{
                printf("%d: No\n",i+1);
            }
        }
        printf("\n");
        free(root);
    }
    return 0;
}

7.1302-Balance Tree

样例输入

3
5
4 3 2 1 5
5
3 4 2 1 5
5
4 2 1 3 5

样例输出

No
Yes
Yes

 思路:跟上题目是同一个类型的,我们只需要学会找二叉树深度,这个题目就挺简单了。

Memory: 4708KTime: 125MS
#include <stdio.h>
#include <algorithm>
using namespace std;
struct Treenode
{
    int val;
    Treenode *l;
    Treenode *r;
};
int flag=0;
Treenode* create(Treenode* t)//二叉树模板
{
    t=new Treenode;
    t->l=nullptr;
    t->r=nullptr;
    return t;
}
Treenode* into(Treenode* t,int val)
{
    if(t==nullptr){
        t=create(t);
        t->val=val;
        return t;
    }
    if(val<t->val){
        t->l=into(t->l,val);
        return t;
    }
    if(val>t->val){
        t->r=into(t->r,val);
        return t;
    }
}
int dfs(Treenode *t)//求深度
{
    if(t==nullptr){
        return 0;
    }
    int left=dfs(t->l);
    int right=dfs(t->r);
    if(abs(left-right)>1){//左子树和右子树深度
        flag=1;
        return max(left,right)+1;
    }
    return max(left,right)+1;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        flag=0;
        int n;
        scanf("%d",&n);
        Treenode *root=nullptr;
        for(int i=0;i<n;i++){
            int nums;
            scanf("%d",&nums);
            root=into(root,nums);
        }
        dfs(root);
        if(flag==0){
            printf("Yes\n");
        }
        else{
            printf("No\n");
        }
    }
    return 0;
}

8.1369-Black White Chess

样例输入

5
0000000000000000
1111111111111111
0000111100001111
1000000000000000
1100000000000011

样例输出

0
0
2
-1
4

 思路:一遍bfs即可,找到所有的可能,计算最小。

Memory: 7652KTime: 514MS
#include <iostream>
#include <queue>
#include <unordered_map>
typedef long long ll;
using namespace std;
unordered_map<string,ll>hashmap;
int a[10001];
string cows(string s,int n)//行
{
    for(int i=n*4;i<n*4+4;i++){
        if(s[i]=='0'){
            s[i]='1';
        }
        else{
            s[i]='0';
        }
    }
    return s;
}
string rows(string s,int n)//列
{
    for(int i=n;i<n+16;i+=4){
        if(s[i]=='0'){
            s[i]='1';
        }
        else{
            s[i]='0';
        }
    }
    return s;
}
string mids(string s,int n)//四个
{
    for(int i=n;i<n+2;i++){
        if(s[i]=='0'){
            s[i]='1';
        }
        else{
            s[i]='0';
        }
    }
    for(int i=n+4;i<n+6;i++){
        if(s[i]=='0'){
            s[i]='1';
        }
        else{
            s[i]='0';
        }
    }
    return s;
}
void bfs()//bfs
{
    string s;
    pair<string,ll>res;
    queue<pair<string,ll>>p;
    int ans=1;
    for(int i=0;i<16;i++){//初始化两个原状态
        s+='0';
    }
    res.first=s;
    res.second=0;
    p.push(res);
    for(int i=0;i<16;i++){
        s[i]='1';
    }
    res.first=s;
    res.second=0;
    p.push(res);
    while(!p.empty()){
        string sp=p.front().first;
        int x=p.front().second;
        p.pop();
        if(hashmap[sp]!=0){//maps储存是否已经出现
            continue;
        }
        else{
            hashmap[sp]=ans++;
        }
        a[hashmap[sp]]=x;//x是最小次数
        //cout<<sp<<" "<<x<<endl;
        for(int i=0;i<4;i++){
            p.push({cows(sp,i),x+1});
        }
        for(int i=0;i<4;i++){
            p.push({rows(sp,i),x+1});
        }
        for(int i=0;i<3;i++){
            p.push({mids(sp,i),x+1});
        }
        for(int i=4;i<7;i++){
            p.push({mids(sp,i),x+1});
        }
        for(int i=8;i<11;i++){
            p.push({mids(sp,i),x+1});
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    bfs();
    while(t--){
        string m;
        cin>>m;
        if(hashmap[m]==0){
            cout<<-1<<endl;
        }
        else{
            cout<<a[hashmap[m]]<<endl;
        }

    }
    return 0;
}

9.1370-Ball

样例输入

4
3 2
1 2
2 3

3 2
1 2
1 3

7 6
1 3
2 3
3 4
4 5
5 6 
5 7

5 6
1 2
1 3
1 4
1 5
2 3
2 4

样例输出

2
0
4
0

 思路:当时我是真的没有想到用Floyd算法,我们先把每个边根据Floyd初始化,然后使用一次Floyd,然后看每个点与其他的点的距离是否是无限大,如果是无限大那么说明出度或者入度就0,否则入度或者出度+1,最后再比较入度和出度是否都是一半。

Memory: 1248KTime: 77MS
#include <stdio.h>
#include <string.h>
#include <limits.h>
using namespace std;
int d[101][101];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m;
        scanf("%d%d",&n,&m);
        memset(d,0,sizeof(d));
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){//Floyd初始化
                if(i==j){
                    d[i][j]=0;
                }
                else{
                    d[i][j]=INT_MAX/2;
                }
            }
        }
        for(int i=0;i<m;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            d[a-1][b-1]=1;
        }
        for(int i=0;i<n;i++){//Floyd
            for(int j=0;j<n;j++){
                for(int k=0;k<n;k++){
                    if(d[j][k]>d[j][i]+d[i][k]){
                        d[j][k]=d[j][i]+d[i][k];
                    }
                }
            }
        }
        //cout<<d[0][1]<<endl;
        //cout<<INT_MAX/2;
        int flag=0;
        for(int i=0;i<n;i++){
            int a=0;
            for(int j=0;j<n;j++){
                if(d[i][j]!=0&&d[i][j]!=INT_MAX/2){//如果不是无限大,说明有出度或者入度
                    if(d[i][j]>0){
                        /*if(i==1)
                        cout<<i<<" "<<j<<" "<<d[i][j]<<endl;*/
                        a++;
                    }
                }
            }
            if(a==(n-1)/2){//如果入度或者出度中的一个等于中间,那么继续寻找出度或者入度
                a=0;
                for(int k=0;k<n;k++){
                    if(d[k][i]!=0&&d[k][i]!=INT_MAX/2){
                        a++;
                    }
                }
                if(a==(n-1)/2){//两个都是的话说明是中间的了
                    flag=1;
                    printf("%d\n",i+1);
                }
            }
        }
        if(flag==0){
            printf("%d\n",0);
        }
    }
    return 0;
}

10.1378-Blocks

以前的博客有,可以去翻我以前的题解。

11.1387-打字机

不想写wwww

12.1389-二叉查找树

样例输入

2
5
3 2 1 4 5
5
4 5 3 2 1

样例输出

1
2

思路:模板题,没什么说的。

Memory: 14952KTime: 546MS
#include <stdio.h>
#include <algorithm>
using namespace std;
struct Treenode
{
    int val;
    Treenode *l;
    Treenode *r;
};
int mins=0;
Treenode* create(Treenode* t)
{
    t=new Treenode;
    t->l=nullptr;
    t->r=nullptr;
    return t;
}
Treenode* into(Treenode* t,int val)
{
    if(t==nullptr){
        t=create(t);
        t->val=val;
        return t;
    }
    if(val<t->val){
        t->l=into(t->l,val);
        return t;
    }
    if(val>t->val){
        t->r=into(t->r,val);
        return t;
    }
}
int dfs(Treenode *t)
{
    if(t==nullptr){
        return 0;
    }
    int left=dfs(t->l);
    int right=dfs(t->r);
    mins=max(abs(left-right),mins);
    return max(left,right)+1;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        mins=0;
        int n;
        scanf("%d",&n);
        Treenode *root=nullptr;
        for(int i=0;i<n;i++){
            int nums;
            scanf("%d",&nums);
            root=into(root,nums);
        }
        dfs(root);
        printf("%d\n",mins);
    }
    return 0;
}

13.1398-积木II

样例输入

2
6 3
9 3

样例输出

2
6

 思路:其实跟积木I没什么区别,我们想一想,积木经过全排列后,我们只需要从中拿出一段排好序列放到后面,就是这个题目的意思了,那么拿出的方式有C\binom{1}{m}+C\binom{2}{m}+C\binom{3}{m}.......+C\binom{m-1}{m}=2^{m}-2

是不是很神奇?那你就大错特错了,其实题解上这个公式思路是对的,但是运算并不是这个,其实实际的m应该是m-1,因为你排好序后最后最大的那一位是不能动的。

Memory: 1732KTime: 312MS
#include <stdio.h>
#include <string.h>
#include <math.h>
using namespace std;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m;
        int dp[110][11][110];
        memset(dp,0,sizeof(dp));
        dp[1][1][1]=1;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                for(int k=1;k<=i;k++){
                    if(j==1){
                        if(i==k)dp[i][j][k]=1;
                        else dp[i][j][k]=0;
                    }
                    else{
                        for(int s=k-1;s>=1;s--){
                            dp[i][j][k]+=dp[i-k][j-1][s];
                        }
                    }
                }
            }
        }
        int res=0;
        for(int i=1;i<=n;i++){
            res+=dp[n][m][i];
        }
        res*=pow(2,m-1)-2;//最终结果应该是m-1
        printf("%d\n",res);
    }
    return 0;
}

14.1409-Splite

样例输入

2
5 2
1 2 3 4 5
5 3
1 5 2 4 3

样例输出

17
15

思路:典型的dp题,一定要注意初始化啊!!!!

Memory: 1480KTime: 0MS
#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;

int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int a[51];
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        int dp[55][55];
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            dp[i][1]=abs(a[i]-a[1])*i;
        }
        dp[1][1]=a[1];
        for(int i=1;i<=n;i++){
            for(int k=1;k<=m;k++){
                if(k==1){
                    continue;
                }
                for(int j=i-1;j>=0;j--){
                    if(k-1>j){
                        dp[i][k]=max(dp[i][k],dp[i-1][k-1]+a[i]);
                        continue;
                    }
                    dp[i][k]=max(dp[i][k],max(dp[i-1][k-1]+a[i],dp[j][k-1]+(i-j)*abs(a[j+1]-a[i])));
                }
            }
        }
        printf("%d\n",dp[n][m]);
    }
    return 0;
}

15.1410-Anniversary

样例输入

1
4 7 2
1 2 7
1 3 2
2 3 1
3 2 2
3 4 5
2 1 3
4 2 3

样例输出

9

 思路:构造一个正图,一个反图,分别使用dijkstra算法。

Memory: 9228KTime: 1375MS
#include <stdio.h>
#include <queue>
#include <string.h>
#include <algorithm>
#include <limits.h>
using namespace std;
int s[1001][1001];
int s2[1001][1001];
int d[1001];
int vis[1001], n, m, e;
int p[1001],g[1001];
struct node
{
    int a, b;
    bool operator<(const node&c)const
    {
        return b > c.b;
    }
};
void djstr(int st)
{
    fill(d, d + 1001, INT_MAX/2);
    d[st] = 0;
    priority_queue<node>q;
    node t;
    t.a = st, t.b = 0;
    q.push(t);
    memset(vis, 0, sizeof(vis));
    while (!q.empty()) {
        node x = q.top();
        q.pop();
        int a = x.a;
        if (vis[a] == 1) {
            continue;
        }
        vis[a] = 1;
        for (int i = 0;i < n;i++) {
            if (!vis[i] && s[a][i] < INT_MAX/2) {
                if (d[i] > d[a] + s[a][i]) {
                    d[i] = d[a] + s[a][i];
                    node temp;
                    temp.a = i;
                    temp.b = d[i];
                    q.push(temp);
                }
            }
        }
    }
}
void djstr1(int st)
{
    fill(d, d + 1001, INT_MAX / 2);
    d[st] = 0;
    priority_queue<node>q;
    node t;
    t.a = st, t.b = 0;
    q.push(t);
    memset(vis, 0, sizeof(vis));
    while (!q.empty()) {
        node x = q.top();
        q.pop();
        int a = x.a;
        if (vis[a] == 1) {
            continue;
        }
        vis[a] = 1;
        for (int i = 0;i < n;i++) {
            if (!vis[i] && s2[a][i] < INT_MAX / 2) {
                if (d[i] > d[a] + s2[a][i]) {
                    d[i] = d[a] + s2[a][i];
                    //printf("%d ", d[i]);
                    node temp;
                    temp.a = i;
                    temp.b = d[i];
                    q.push(temp);
                }
            }
        }
    }
}
int main()
{
    int t;
    scanf("%d", &t);
    while (t--) {
        memset(p, 0, sizeof(p));
        memset(g, 0, sizeof(g));
        fill(s[0], s[0] + 1001 * 1001, INT_MAX/2);
        fill(s2[0], s2[0] + 1001 * 1001, INT_MAX / 2);
        scanf("%d%d%d", &n, &m, &e);
        for (int i = 0;i < m;i++) {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            if (s[x - 1][y - 1] > z) {
                s[x - 1][y - 1] = z;
                s2[y - 1][x - 1] = z;
            }

        }
        djstr(e - 1);
        for(int i = 0;i < n;i++) {
            g[i] = d[i];//e到各个节点
        }
        
        djstr1(e - 1);
        for (int i = 0;i < n;i++) {
            p[i] = d[i];
        }
        int res = -1;
        for (int i = 0;i < n;i++) {
            if (i == e - 1) continue;
            int ans = p[i] + g[i];
            //printf("%d\n", ans);
            res = max(res, ans);
        }
        printf("%d\n", res);
    }
    return 0;
}

16.消星星-1418

输出

对于每个样例,每行输出一个答案,表示消灭所有星星至少需要多少能量。

样例输入

2
2 2
ab
ba
3 3
aab
cab
ccb

样例输出

4
3

思路:dfs即可,遍历完直接就可以退出。

Memory: 2188KTime: 125MS
#include <stdio.h>
#include <string.h>
using namespace std;
char s[1001][1001];
int nums=0,n,m;
void dfs(int x,int y,char a)
{
    if(x>=n||x<0||y>=m||y<0||s[x][y]==0||s[x][y]!=a){
        return;
    }
    s[x][y]=0;
    nums++;
    dfs(x+1,y,a);
    dfs(x-1,y,a);
    dfs(x,y+1,a);
    dfs(x,y-1,a);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        memset(s,0,sizeof(s));
        nums=0;
        int res=0;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++){
            scanf("%s",s[i]);
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(s[i][j]==0){
                    continue;
                }
                if(nums==n*m){
                    break;
                }
                dfs(i,j,s[i][j]);
                res++;
            }
            if(nums==n*m){//遍历全部即可退出
                break;
            }
        }
        printf("%d\n",res);
    }
    return 0;
}

17.1428-Train

样例输入

2
3 10 10
6 4 9
2 7 4
8 3 6
3 10 10
11 1 1
2 12 2
13 13 3

样例输出

10
0

思路:典型的背包dp问题,如果不明白的可以去搜索01背包 问题。

Memory: 1616KTime: 139MS
#include <iostream>
#include <string.h>
using namespace std;
typedef long long ll;
struct node
{
    ll v,x,w;
}res[1001];
ll dp[101][101];
int main()
{
    ll t;
    cin>>t;
    while(t--){
        ll n,m,s;
        cin>>n>>m>>s;
        for(ll i=1;i<=n;i++){
            cin>>res[i].v>>res[i].x>>res[i].w;
        }

        memset(dp,0,sizeof(dp));
        for(ll i=1;i<=n;i++){
            for(ll j=m;j>=res[i].v;j--){    //转移方程,要么装,要么不装,只有两种选择
                for(ll k=s;k>=res[i].x;k--){//不装那就是前一个状态,装就是前一个状态+现在状态
                    if(j>=res[i].v&&k>=res[i].x){
                        dp[j][k]=max(dp[j][k],dp[j-res[i].v][k-res[i].x]+res[i].w);
                    }
                    else{
                        dp[j][k]=dp[j][k];
                    }
                }
            }
        }
        cout<<dp[m][s]<<endl;
    }
    return 0;
}

 18.1433-Swap Digits 不会......

19.1434-Lost Digits

样例输入

2
7?
?7

样例输出

2
1

 思路:dp题,转移方程看我代码,这里不好敲。

Memory: 1532KTime: 15MS
#include <iostream>
#include <string.h>
using namespace std;

int main()
{
    int t;
    cin>>t;
    while(t--){
        int dp[20][8];
        memset(dp,0,sizeof(dp));
        string s;
        cin>>s;
        int n=s.size();
        if(n==1&&s[0]=='?'){
            cout<<2<<endl;
            continue;
        }
        if(s[0]!='?'){
            dp[0][(s[0]-'0')%7]=1;
        }
        else{
            for(int i=0;i<10;i++){
                dp[0][i%7]++;
            }
            dp[0][0]--;
        }
        for(int i=1;i<=n;i++){
            if(s[i]=='?'){//如果是问号,那么对0-9都得做贡献
                for(int k=0;k<10;k++){
                    for(int j=0;j<7;j++){
                        dp[i][(10*j+k)%7]+=dp[i-1][j];//状态转移方程
                    }
                }
            }
            else{
                for(int j=0;j<7;j++){//否则只对指定做贡献
                    dp[i][(10*j+(s[i]-'0'))%7]+=dp[i-1][j];
                }
            }
        }
        cout<<dp[n-1][0]<<endl;
    }
    return 0;
}

 20.1435-Path

样例输入

2
3 2 1
1 2 1
2 3 2
2
3 2 2
1 2 1
2 3 2
1 3

样例输出

3
1

思路:还是dijkstra算法,只不过要用超级原点,什么是超级原点呢?就是一个虚拟的点,要求他对所有起点的距离都是0,那么这样的话求出的距离不就是所有起点到终点的距离么?然后dijkstra算法就能求出最短的距离,也是很不错了。

Memory: 5372KTime: 874MS
#include <stdio.h>
#include <limits.h>
#include <algorithm>
#include <queue>
#include <string.h>
using namespace std;
typedef long long ll;
int s[1011][1011];
int d[1011];
int vis[1011];
int n,m,k;
struct node
{
    int a, b;
    bool operator<(const node&c)const
    {
        return b > c.b;
    }
};
void djstr(int k)
{
    fill(d, d + 1011, INT_MAX/2);
    priority_queue<node>q;
    while(k--){
        int a;
        scanf("%d",&a);
        d[a]=0;
        q.push((node){a,0});//所有点全部入栈,模拟超级原点,其他算法和dijkstra没有任何区别 
    }
    memset(vis, 0, sizeof(vis));
    while (!q.empty()) {
        node x = q.top();
        q.pop();
        int a = x.a;
        if (vis[a] == 1) {
            continue;
        }
        vis[a] = 1;
        for (int i = 1;i <= n;i++) {
            if (!vis[i] && s[a][i] < INT_MAX/2) {
                if (d[i] > d[a] + s[a][i]) {
                    d[i] = d[a] + s[a][i];
                    node temp;
                    temp.a = i;
                    temp.b = d[i];
                    q.push(temp);
                }
            }
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        fill(s[0],s[0]+1011*1011,INT_MAX/2);
        scanf("%d%d%d",&n,&m,&k);
        for(int i=0;i<m;i++){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            if(s[a][b]>c){
                s[a][b]=c;
                s[b][a]=c;
            }
        }
        djstr(k);
        ll res=0;
        for(int i=1;i<=n;i++){
            res+=(ll)d[i];
        }
        if(res>=INT_MAX/2){
            printf("-1\n");
            continue;
        }
        printf("%lld\n",res);
    }
    return 0;
}

  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值