1. 程式人生 > 其它 >寒假集訓三補題與題解

寒假集訓三補題與題解

A

分析

我們可以嘗試依次把每一隻小貓分配到一輛已經租用的纜車上,或者租用一輛纜車安置這種小貓

AC程式碼

#include<iostream>
#include<algorithm>
#define N 20
using namespace std;
int n,m;
int cat[N],sum[N],ans=N;
bool cmp(int a,int b)
{
    return a>b;
}
void dfs(int u,int k)//第u只貓,k輛車
{
    if(k>=ans) return ;
    if(u==n) 
    {
        ans
=k; return ; } for(int i=0;i<k;i++) if(sum[i]+cat[u]<=m) { sum[i]+=cat[u]; dfs(u+1,k); sum[i]-=cat[u]; } //再來輛車 sum[k]=cat[u]; dfs(u+1,k+1); sum[k]=0; } int main() { cin>>n>>m; for(int i=0;i<n;i++) cin
>>cat[i]; sort(cat,cat+n,cmp); dfs(0,0); cout<<ans<<endl; return 0; }

B

分析

因為0到1的距離就是1到0的距離,比較暴力的想法是對每個1跑一下bfs,但是顯然會超時,多源BFS能很好的解決這個問題,因為如果我們把所有源點加入佇列後,跑出來的路徑距離依然是最短路,因為對於每個源點派生出來的分支,只在每一層上遍歷的順序不同,對於不同深度(即距離),也是遵循從上至下,所以跑出來的距離依然是最短路~。~

AC程式碼

#include<iostream>
#include
<algorithm> #include<cstring> #include<queue> using namespace std; typedef pair<int, int> PII; char a[1009][1009]; int g[1009][1009]; int n,m; queue<PII> p; void bfs() { //for(int i=0;i<n;i++) // for(int j=0;j<m;j++) // { // //cin>>a[i][j]; // if(a[i][j]=='1') // { p.push({i,j}); // g[i][j]=0;} // } int dx[4]={1,0,-1,0},dy[4]={0,-1,0,1}; while(p.size()) { PII t; t=p.front(); p.pop(); for(int i=0;i<4;i++) { int xix=t.first+dx[i],xiy=t.second+dy[i]; if(xix>=0&&xix<n&&xiy>=0&&xiy<m&&g[xix][xiy]==-1) { g[xix][xiy]=g[t.first][t.second]+1; p.push({xix,xiy}); } } } } int main() { memset(g, -1, sizeof g); cin>>n>>m; for(int i=0;i<n;i++) for(int j=0;j<m;j++) { cin>>a[i][j]; if(a[i][j]=='1') { p.push({i,j}); g[i][j]=0;} } bfs(); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) cout<<g[i][j]<<" "; puts(""); } return 0; }

C

分析

搜尋順序:依次列舉每個字元對應哪個數字
剪枝:
1.從低位向高位依次考慮每一位:
a,b,c,t
被加數 加數 和 進位
(a+b+t) mod n=c

2.由於和也是n位數 ,因此最高位不可以有進位

3.從最低位開始列舉每個未知數

path[N]每個字母對應的數字
q[N] 從低位到高位字母出現的順序
st[N] 每個數字有沒有被用過

AC程式碼

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=30;
int n;
int path[N],q[N];
char e[3][N];
bool st[N];
bool check()
{
    for(int i=n-1,t=0;i>=0;i--)
    {
        int a=e[0][i]-'A',b=e[1][i]-'A',c=e[2][i]-'A';
        if(path[a]!=-1&&path[b]!=-1&&path[c]!=-1)
        {
            a=path[a];b=path[b];c=path[c];
            if(t!=-1)
            {
                if((a+b+t)%n!=c) return false;
                if(!i&&a+b+t>=n) return false;
                t=(a+b+t)/n;
            }
            else 
            {
                if((a+b)%n!=c&&(a+b+1)%n!=c) return false;
                if(!i&&a+b>=n) return false;
            }
        }
        else t=-1;
    }
    
   return true; 
}
bool dfs(int u)
{
    if(u==n) return true;
    for(int i=0;i<n;i++)
    if(!st[i])
    {
        st[i]=true;
        path[q[u]]=i;
        if(check()&&dfs(u+1)) return true;
        st[i]=false;
        path[q[u]]=-1;
        
    }
    return false;
    
}
int main()
{
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=0;i<3;i++)
      cin>>e[i];
      for(int i=n-1,k=0;i>=0;i--)
        for(int j=0;j<3;j++)
        {
            int t=e[j][i]-'A';
            if(!st[t]) 
            {
                st[t]=true;
                q[k++]=t;
            }
            
        }
    memset(st,0,sizeof st);
    memset(path,-1,sizeof path);
    dfs(0);
    for(int i=0;i<n;i++)
       cout<<path[i]<<" ";
    
return 0;
    
}

F

分析

Floyd
1.本題的思路就是考慮最小環裡面節點編號最大的節點為k,且環裡面與k相連的兩個點為i,j,環的長度為g[i][k]+g[k][j]+d[j][i];

2.則d[j][i]則表示j到i且經過的節點編號小於k,因為在環中k就是最大的,只能經過小於k的節點了;

3.則這與floyd中k次迴圈開始前的d[i][j]意義相同;

4.那就不妨在floyd的第一重迴圈就求一下以k為最大節點編號的環的長度,注意這裡的k必須與節點的意義一樣:0-n-1或1-n;

AC程式碼

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=110,INF=0x3f3f3f;
int n,m;
int d[N][N],g[N][N];
int pos[N][N],path[N],cnt;
void yoy(int a,int b)
{
    if(pos[a][b]==0) return ;
    int c=pos[a][b];
    yoy(a,c);
    path[cnt++]=c;
    yoy(c,b);
}
int main()
{
    cin>>n>>m;
    memset(g,0x3f,sizeof g);
    for(int i=1;i<=n;i++) g[i][i]=0;
    while(m--)
    {
        int a,b,c;
          cin>>a>>b>>c;
        g[a][b]=g[b][a]=min(g[a][b],c);
    }
    int res=INF;
    memcpy(d,g,sizeof g);
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<k;i++)
            for(int j=i+1;j<k;j++)
                if((long long)d[i][j]+g[j][k]+g[k][i]<res)
                {
                    res=d[i][j]+g[j][k]+g[k][i];
                    cnt=0;
                    path[cnt++]=k;
                    path[cnt++]=i;
                    yoy(i,j);
                    path[cnt++]=j;
                }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(d[i][k]+d[k][j]-d[i][j]<0)
                {
                    d[i][j]=d[i][k]+d[k][j];
                    pos[i][j]=k;
                }
    }
    if(res==INF) puts("No solution.");
    else
    {
        for(int i=0;i<cnt;i++)
            cout<<path[i]<<' ';
        puts("");
    }
return 0;
}

H

分析

給定一組字母的大小關係,要你判斷是否在某一次讀入後,能夠判斷

1.該字母序列有序,並依次輸出;

2.該序列不能判斷是否有序;

3.該序列字母次序之間有矛盾,即有環存在。

而這三種形式的判斷應該遵循這樣的順序:先判斷是否有環(3),再判斷是否有序(1),最後才能判斷是否能得出結果(2)。

注意:對於(2)必須遍歷完整個圖!!,而(1)和(3)一旦得出結果,對後面的輸入就不用做處理了。

AC程式碼

#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
vector<int>G[30];//儲存圖
int in[30];//入度
char ans[30];
int in2[30];//複製上邊的度。因為中間會牽扯到度的更改
int i;
int n,m;
int topu()
{
    bool logal=true;//表示是否是全排列
    memcpy(in2,in,sizeof(in));//進行復制操作
    queue<int>Q;
    int cnt=0;//進行數個數
    for(int i=0;i<m;i++)
    {
        if(in[i]==0)
            Q.push(i);
    }
    while(!Q.empty())
    {
        if(Q.size()>1)
            logal=false;
 
 
        int u=Q.front();
        Q.pop();
        ans[cnt++]=u+'A';
 
 
        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i];
            if(--in2[v]==0)//寫錯了
                Q.push(v);
        }
    }
    int result=0;
    if(cnt<m)
        result=-1;//說明存在環
    else if(logal==true)//全序
        result=1;
    return result;
}
int main()
{
    string s[1030];
    int flag;
    while(cin>>m>>n,n&&m)
    {
        memset(in,0,sizeof(in));
        if(m==0&&n==0)
            break;
        for(i=0;i<m;i++)
        {
            G[i].clear();
        }
        for( i=0;i<n;i++)
        {
            cin>>s[i];
        }
        for(i=0;i<n;i++)
        {
            int u=s[i][0]-'A',v=s[i][2]-'A';
            G[u].push_back(v);
            ++in[v];
            if((flag=topu())!=0)//說明找到了一個全序,或者不滿足的條件
                break;
        }
        ans[m]=0;
       // cout<<flag<<endl<<"*****"<<endl;
        if(flag==1) printf("Sorted sequence determined after %d relations: %s.\n",i+1,ans);
        else if(flag==0) printf("Sorted sequence cannot be determined.\n");
        else if(flag==-1) printf("Inconsistency found after %d relations.\n",i+1);
    }
    return 0;
}