zoukankan      html  css  js  c++  java
  • {purple9}

    {DP}

    A Spy in the Metro

     UVA - 1025 

    has_train那块搞了挺久的。。。

     1 #include <cstdio>
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4 const int maxn=260;
     5 const int INF=0x3f3f3f3f;
     6 int t[maxn],curt;
     7 int has_train[1500][55][2];
     8 int dp[220][55];
     9 int n,T,m1,m2;
    10 
    11 int main()
    12 {
    13     int kase=0;
    14     while(scanf("%d",&n)&&n)
    15     {
    16         memset(has_train,0,sizeof(has_train));
    17         scanf("%d",&T);
    18         for(int i=0;i<n-1;i++) scanf("%d",&t[i]);
    19         scanf("%d",&m1);
    20         for(int i=0;i<m1;i++)
    21         {
    22             scanf("%d",&curt);
    23             has_train[curt][0][0]=1;
    24             for(int j=0;j<n-1;j++) {
    25                 curt+=t[j];
    26                 has_train[curt][j+1][0]=1;
    27             }
    28         }
    29         scanf("%d",&m2);
    30         for(int i=0;i<m2;i++)
    31         {
    32             scanf("%d",&curt);
    33             has_train[curt][n-1][1]=1;
    34             for(int j=n-1;j>0;j--) {
    35                 curt+=t[j-1];
    36                 has_train[curt][j-1][1]=1;
    37             }
    38         }
    39 
    40         for(int i=0;i<n-1;i++) dp[T][i]=INF;
    41         dp[T][n-1]=0;
    42 
    43         for(int i=T-1;i>=0;i--)
    44         for(int j=0;j<n;j++){
    45             dp[i][j]=dp[i+1][j]+1; //等待
    46             if(j<n-1&&has_train[i][j][0]&&i+t[j]<=T)
    47                 dp[i][j]=min(dp[i][j],dp[i+t[j]][j+1]);  //
    48             if(j>0&&has_train[i][j][1]&&i+t[j-1]<=T)
    49                 dp[i][j]=min(dp[i][j],dp[i+t[j-1]][j-1]); //
    50         }
    51         printf("Case Number %d: ",++kase);
    52         if(dp[0][0]>=INF) puts("impossible");
    53         else printf("%d
    ",dp[0][0]);
    54     }
    55 
    56 }
    View Code

    The Tower of Babylon

     UVA - 437 

    最长上升子序列

    排序有点懵。。。

     1 #include <cstdio>
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4 const int maxn=260;
     5 const int INF=0x3f3f3f3f;
     6 int dp[100];
     7 struct node
     8 {
     9     int a,b;
    10     int h;
    11     bool operator <(const node &x)
    12     {
    13         if(b!=x.b) return b>x.b;
    14         else return a>x.a;
    15     }
    16 }sq[100];
    17 int cnt=0;
    18 int n;
    19 
    20 int main()
    21 {
    22     int kase=0;
    23     while(scanf("%d",&n)&&n)
    24     {
    25         cnt=0;
    26         for(int i=0;i<n;i++)
    27         {
    28             int a,b,h;
    29             scanf("%d%d%d",&a,&b,&h);
    30             sq[cnt++]={max(a,b),min(a,b),h};
    31             sq[cnt++]={max(a,h),min(a,h),b};
    32             sq[cnt++]={max(b,h),min(b,h),a};
    33         }
    34         sort(sq,sq+cnt);
    35         int ans=0;
    36         for(int i=0;i<cnt;i++)
    37         {
    38             dp[i]=sq[i].h;
    39             for(int j=0;j<i;j++) if(sq[i].a<sq[j].a&&sq[i].b<sq[j].b)
    40                 dp[i]=max(dp[i],dp[j]+sq[i].h);
    41             ans=max(ans,dp[i]);
    42         }
    43         printf("Case %d: maximum height = %d
    ",++kase,ans);
    44     }
    45 
    46 }
    View Code

    Tour

     UVA - 1347

    lrjp269。题解链接

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=1010;
     4 double x[maxn],y[maxn];
     5 double dist[maxn][maxn];
     6 double dp[maxn][maxn];
     7 
     8 int main()
     9 {
    10     int n;
    11     while(scanf("%d",&n)!=EOF) {
    12 
    13         for(int i=1;i<=n;i++) {
    14             scanf("%lf%lf",&x[i],&y[i]);
    15         }
    16 
    17         for(int i=1;i<=n;i++) {
    18             for(int j=1;j<=n;j++) {
    19                 dist[i][j] = sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
    20             }
    21         }
    22 
    23         for(int i=n-1;i>=2;i--) {
    24             for(int j=1;j<i;j++) {
    25                 if(i==n-1)
    26                     dp[i][j] = dist[i][n] + dist[j][n];
    27                 else dp[i][j] = min(dist[i][i+1]+dp[i+1][j],dist[j][i+1]+dp[i+1][i]);
    28             }
    29         }
    30         printf("%.2lf
    ",dp[2][1]+dist[1][2]);
    31 
    32     }
    33 
    34     return 0;
    35 }
    COPY

    Jin Ge Jin Qu hao

     UVA - 12563

    背包问题

    注意题目给的数据可能是误导(过大),要分析实际数据可能大小。 // T<180*n+678<10000

    要求首先是数目最多,其次才是时间最长。。。这块没注意WA了

     1 #include <cstdio>
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4 int dp[10010],cnt[10010];
     5 int n,T,a;
     6 
     7 int main()
     8 {
     9     int t,kase=0;
    10     scanf("%d",&t);
    11     while(t--)
    12     {
    13         memset(dp,0,sizeof(dp));
    14         memset(cnt,0,sizeof(cnt));
    15         scanf("%d%d",&n,&T);   // T<180*n+678<10000!!!
    16         for(int i=0;i<n;i++)
    17         {
    18             scanf("%d",&a);
    19             for(int j=T;j>=a;j--)
    20                 if(cnt[j]<cnt[j-a]+1||cnt[j]==cnt[j-a]+1&&dp[j]<dp[j-a]+a)  //
    21             {
    22                 dp[j]=dp[j-a]+a;
    23                 cnt[j]=cnt[j-a]+1;
    24             }
    25         }
    26         printf("Case %d: %d %d
    ",++kase,cnt[T-1]+1,dp[T-1]+678);
    27     }
    28 }
    View Code

    Partitioning by Palindromes

     UVA - 11584 

    判断回文串的时候失了智。。。

     1 #include <cstdio>
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4 const int maxn=1010;
     5 bool s[maxn][maxn];
     6 char c[maxn];
     7 int d[maxn];
     8 int n;
     9 
    10 int main()
    11 {
    12     scanf("%d",&n);
    13     while(n--)
    14     {
    15         memset(s,0,sizeof(s));
    16         scanf("%s",c+1);
    17         int len=strlen(c+1)+1;
    18         for(int i=1;i<len;i++){  //=_=||
    19                 d[i]=i;
    20            for(int j=i;j>0;j--)
    21            {
    22                if(i==j) s[i][j]=true;
    23                else if(i-j==1&&c[i]==c[j]) s[j][i]=true;
    24                else if(s[j+1][i-1]&&c[i]==c[j]) s[j][i]=true;
    25                else s[j][i]=false;
    26            }
    27         }
    28         d[0]=0;
    29         for(int i=1;i<len;i++)
    30             for(int j=0;j<i;j++)
    31                 if(s[j+1][i])  d[i]=min(d[i],d[j]+1);
    32             printf("%d
    ",d[len-1]);
    33     }
    34 
    35 }
    View Code

    Color Length

     UVA - 1625

    大概理解了写不出来代码。。。题解链接

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 using namespace std;
     5 const int inf=0x3f3f3f3f;
     6 const int maxn=5005;
     7 char a[maxn],b[maxn];
     8 int len1,len2;
     9 int first[255][3],last[255][3];
    10 int dp[maxn][maxn];
    11 int c[maxn][maxn];
    12 int main()
    13 {
    14     int T;
    15     scanf("%d",&T);
    16     for(int kase=1;kase<=T;++kase)
    17     {
    18         scanf("%s%s",a+1,b+1);
    19         len1=strlen(a+1),len2=strlen(b+1);
    20         for(int i='A';i<='Z';i++)
    21         {
    22             first[i][1]=first[i][2]=inf;
    23             last[i][1]=last[i][2]=-1;
    24         }
    25         for(int i=0;i<=len1;i++)
    26             for(int j=0;j<=len2;j++)
    27             c[i][j]=dp[i][j]=0;
    28         for(int i=1;i<=len1;i++)
    29         {
    30             if(first[a[i]][1]==inf) first[a[i]][1]=i;
    31             last[a[i]][1]=i;
    32         }
    33         for(int i=1;i<=len2;i++)
    34         {
    35             if(first[b[i]][2]==inf) first[b[i]][2]=i;
    36             last[b[i]][2]=i;
    37         }
    38         for(int i=0;i<=len1;i++)
    39         {
    40             if(i)
    41             {
    42                 c[i][0]=c[i-1][0];
    43                 if(first[a[i]][1]==i) c[i][0]++;
    44                 if(last[a[i]][1]==i&&last[a[i]][2]==-1) c[i][0]--;
    45             }
    46             for(int j=1;j<=len2;j++)
    47             {
    48                 c[i][j]=c[i][j-1];
    49                 if(first[b[j]][2]==j&&first[b[j]][1]>i) c[i][j]++;
    50                 if(last[b[j]][2]==j&&last[b[j]][1]<=i) c[i][j]--;
    51             }
    52         }
    53         for(int i=0;i<=len1;i++)
    54             for(int j=0;j<=len2;j++)
    55             {
    56                 if(i>0&&j>0) dp[i][j]=min(dp[i-1][j],dp[i][j-1])+c[i][j];
    57                 else if(i==0&&j>0) dp[i][j]=dp[i][j-1]+c[i][j];
    58                 else if(i>0&&j==0) dp[i][j]=dp[i-1][j]+c[i][j];
    59             }
    60         printf("%d
    ",dp[len1][len2]);
    61     }
    62 }
    COPY

    Another Crisis

     UVA - 12186 

     树dp

    dfs,每个节点选择较小的k个子节点即可。

    代码有误!!

     1 #include <cstdio>
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4 const int maxn=100010;
     5 
     6 struct edge
     7 {
     8     int v,nex;
     9 }e[maxn];
    10 int head[maxn];
    11 int cnt,n,t;
    12 void add(int u,int v)
    13 {
    14     e[cnt].v=v;
    15     e[cnt].nex=head[u];
    16     head[u]=cnt++;
    17 }
    18 int dfs(int u)
    19 {
    20     int i=head[u];
    21     if(i==-1) return 1;  //叶子
    22     vector<int> v;
    23     for(;i!=-1;i=e[i].nex)
    24     {
    25         v.push_back(dfs(e[i].v));
    26     }
    27     int len=v.size();
    28     int k=(len*t/100)+(len*t%100==0?0:1);  //
    29     int temp=0;
    30     sort(v.begin(),v.end());
    31     for(int j=0;j<k;j++)   //选择较小的k个子节点
    32     {
    33         temp+=v[j];
    34     }
    35     return temp;
    36 }
    37 int main()
    38 {
    39     while(scanf("%d%d",&n,&t)&&(n||t))
    40     {
    41         cnt=0;
    42         memset(head,-1,sizeof(head));
    43         for(int i=1;i<=n;i++)
    44         {
    45             int u;
    46             scanf("%d",&u);
    47             add(u,i);
    48         }
    49         printf("%d
    ",dfs(0));
    50     }
    51     return 0;
    52 }
    View Code

    Party at Hali-Bula

     UVA - 1220

    树dp

    树的最大独立集,并判断是否唯一。

    d[u][1]表示选u,d[u][0]表示不选u

    f[u][1]==1表示选u的情况下唯一,f[u][1]==0表示不唯一

    f[u][0]为不选u的情况下的唯一性

    没仔细读题,,Yes和No输反了=_=||

     1 #include <cstdio>
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4 const int maxn=220;
     5 map<string,int> m;
     6 int n;
     7 struct edge
     8 {
     9     int v;
    10     int nex;
    11 }e[maxn];
    12 int head[maxn];
    13 int cnt=0;
    14 void add(int u,int v)
    15 {
    16     e[cnt].v=v;
    17     e[cnt].nex=head[u];
    18     head[u]=cnt++;
    19 }
    20 string s1,s2;
    21 int d[maxn][2],f[maxn][2];
    22 void dfs(int u)
    23 {
    24     f[u][1]=f[u][0]=1;
    25     for(int i=head[u];i!=-1;i=e[i].nex)
    26     {
    27         int v=e[i].v;
    28         dfs(v);
    29         d[u][0]+=max(d[v][1],d[v][0]);
    30         d[u][1]+=d[v][0];
    31         if(f[v][0]==0) f[u][1]=0;
    32         //下面分三种情况判断f[u][0]
    33         if(d[v][1]==d[v][0]) f[u][0]=0;
    34         if(d[v][1]>d[v][0]&&f[v][1]==0) f[u][0]=0;
    35         if(d[v][0]>d[v][1]&&f[v][0]==0) f[u][0]=0;
    36     }
    37     d[u][1]++;
    38     return ;
    39 }
    40 int main()
    41 {
    42     while(scanf("%d",&n)&&n)
    43     {
    44         m.clear();
    45         int id=2;
    46         cnt=0;
    47         memset(head,-1,sizeof(head));
    48         memset(d,0,sizeof(d));
    49         memset(f,0,sizeof(f));
    50         cin>>s1;
    51         m[s1]=1;
    52         for(int i=1;i<n;i++)
    53         {
    54             cin>>s1>>s2;
    55             if(!m[s1]) m[s1]=id++;
    56             if(!m[s2]) m[s2]=id++;
    57             add(m[s2],m[s1]);
    58         }
    59         dfs(1);
    60         int ans,flag=1;
    61         if(d[1][1]>d[1][0])
    62         {
    63             ans=d[1][1];
    64             if(f[1][1]) flag=1;
    65             else flag=0;
    66         }
    67         else if(d[1][1]<d[1][0])
    68         {
    69             ans=d[1][0];
    70             if(f[1][0]) flag=1;
    71             else flag=0;
    72         }
    73         else ans=d[1][1],flag=0;
    74         printf("%d %s
    ",ans,flag?"Yes":"No");
    75     }
    76     return 0;
    77 }
    View Code

    Perfect Service

     UVA - 1218

    树dp

    第三个状态转移公式不会,难理解。。。

    有些细节做的不好。。。

     1 #include <cstdio>
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4 const int maxn=10010;
     5 int d[maxn][3];
     6 int in[maxn];
     7 struct edge
     8 {
     9     int v,nex;
    10 }e[maxn<<1];
    11 int head[maxn];
    12 int cnt;
    13 void add(int u,int v)
    14 {
    15     e[cnt].v=v;
    16     e[cnt].nex=head[u];
    17     head[u]=cnt++;
    18 }
    19 int n;
    20 void dfs(int u,int f)
    21 {
    22     d[u][2]=10000;  //!!!不合法
    23     d[u][0]=1;
    24     d[u][1]=0;
    25     for(int i=head[u];i!=-1;i=e[i].nex)
    26     {
    27 
    28         int v=e[i].v;
    29         if(v==f) continue;
    30         dfs(v,u);
    31         d[u][0]+=min(d[v][0],d[v][1]);
    32         d[u][1]+=d[v][2];
    33         d[u][2]=min(d[u][2],d[u][1]-d[v][2]+d[v][0]);
    34     }
    35     return ;
    36 }
    37 int main()
    38 {
    39     int u,v;
    40     while(scanf("%d",&n)&&n!=-1)
    41     {
    42         cnt=0;
    43         memset(head,-1,sizeof(head));
    44         memset(d,0,sizeof(d));
    45         memset(in,0,sizeof(in));
    46         for(int i=1;i<n;i++)
    47         {
    48             scanf("%d%d",&u,&v);
    49             add(u,v);
    50             add(v,u);
    51         }
    52         dfs(1,0);
    53         printf("%d
    ",min(d[1][0],d[1][2]));
    54         scanf("%d",&u);
    55         if(u==0) continue;
    56         else break;
    57     }
    58 }
    View Code

    Headmaster's Headache

     UVA - 10817

    状压dp

    m和n输入反了一直WA也是很懵比,对着lrj代码找了好久都没发现。。。

     1 #include <cstdio>
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4 const int INF= 0x3f3f3f3f;
     5 const int maxn=125;
     6 const int maxx=8;
     7 int m,n,s;
     8 int c[maxn],st[maxn],d[maxn][1<<maxx][1<<maxx];
     9 
    10 int dp(int i,int s0,int s1,int s2)
    11 {
    12     if(i==m+n) return s2==(1<<s)-1 ? 0 : INF;
    13     int &ans=d[i][s1][s2];
    14     if(ans>=0) return ans;
    15     ans=INF;
    16     if(i>=m) ans=dp(i+1,s0,s1,s2);  //不选
    17     int m0=st[i]&s0;
    18     int m1=st[i]&s1;
    19     s0^=m0;
    20     s1=(s1^m1)|m0;
    21     s2|=m1;
    22     ans=min(ans,c[i]+dp(i+1,s0,s1,s2)); //
    23     return ans;
    24 }
    25 int main()
    26 {
    27     while(scanf("%d%d%d",&s,&m,&n)&&(s||m||n))
    28     {
    29         memset(d,-1,sizeof(d));
    30         getchar();
    31         for(int i=0;i<m+n;i++)
    32         {
    33             st[i]=0;
    34             string line;
    35             int x;
    36             getline(cin,line);
    37             stringstream ss(line);
    38             ss>>c[i];
    39             while(ss>>x)
    40             {
    41                 x--;
    42                 st[i]|=(1<<x);
    43             }
    44            // cout<<"能教的科目为: ";
    45             //for(int j=0;j<s;j++) if(st[i]&(1<<j)) cout<<j+1<<' ';
    46             //cout<<endl;
    47         }
    48         printf("%d
    ",dp(0,(1<<s)-1,0,0));
    49     }
    50     return 0;
    51 
    52 }
    View Code

    Twenty Questions

     UVA - 1252 

    状压dp

    自己不会写啊。。。

    d[s][a]表示已经问了s中为1的位置,状态为a时最少还需要问几次

    (简言之s保存的是询问过的位置。。。)

    【我们每次把物品中已经询问的位置(即s为1的那些位置)都和状态a一致的选出来,如果只有一个,说明我们已经找到,否则,继续询问备选缩小范围。】

    a是不确定的,每次决策a的那个位置可能是0或1,我们要求的是不管那位0或者1,都可以唯一确定a最少还要问的次数,即两种状态下取较大的次数。

    要求最优决策下的最小次数,每次决策更新最小值ans。

    当所有物品中满足a的个数等于1时,得到一个次数返回比较即可。

     1 #include <cstdio>
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4 
     5 const int maxn = 1 << 12;
     6 const int INF = 0x3f3f3f3f;
     7 
     8 string str;
     9 int w[130];
    10 int d[maxn][maxn];
    11 int m, n;
    12 
    13 int dp(int s, int a)
    14 {
    15     int& ans = d[s][a];
    16     if (ans != INF)  return ans;
    17     int cnt = 0;
    18     for (int i = 0; i<n; i++)
    19         //边界条件判断,如果cnt<=1,则说明能判断出来了
    20     if ((w[i] & s) == a)  cnt++;
    21     if (cnt <= 1){ d[s][a] = 0; return 0; }
    22 
    23     for (int i = 0; i<m; i++)
    24     {
    25         if (s&(1 << i))continue;
    26         ans = min(ans, max(dp(s | 1 << i, a | 1 << i), dp(s | 1 << i, a)) + 1);
    27     }
    28     return ans;
    29 }
    30 
    31 int main()
    32 {
    33     while (cin>>m>>n &&n&&m)
    34     {
    35         memset(w, 0, sizeof(w));
    36         memset(d, INF, sizeof(d));
    37         for (int i = 0; i<n; i++)
    38         {
    39             cin >> str;
    40             for (int j = 0; str[j]; j++)
    41             if (str[j] == '1')  w[i] |= (1 << j);
    42         }
    43         printf("%d
    ", dp(0,0));
    44     }
    45 }
    COPY

    Dropping water balloons

     UVA - 10934

    可以说是很懵比了。。。

    和上一个题有相似之处,就是我们需要判断的结果是一个未知量。如本题气球的硬度,可能为1,2,3,------,n,n+1。

    最坏情况需要测到n楼才知道结果。题目要求确定气球硬度,我们要考虑所有情况。【即我们要求的是最少测几次才可以测到n楼。】

    用d[i][j]表示i个气球j次试验最多测到d[i][j]楼(即运气足够好的情况下可以测到几层楼【这也是题目要求的,最少几次!!】

    (上面这两条红字放一起有点难以理解)


    我们首先要求的是第一次最好在哪一层楼进行测试

    先设第一次为k楼最好(以下八行都是在这个假设下进行的,记为假设一吧)

    如果第一次气球就破,则说明i-1个气球j-1次试验测(即d[i-1][j-1])需要测到k-1层楼才可以,即d[i-1][j-1]==k-1。证明如下:

    反证法:

    假设d[i-1][j-1]=x<k-1,则x楼到k楼之间是断层,说明第一次测试的k楼没有意义,k不是最好,与假设一矛盾,故d[i-1][j-1]>=k-1

    假设d[i-1][j-1]=x>k-1,即d[i-1][j-1]>=k,说明i-1个气球j-1次就可以测到k+层楼了,第一次测试的k层楼没有意义,k不是最好,与假设一矛盾,故d[i-1][j-1]<=k-1

    综上,d[i-1][j-1]==k-1。

    即i个气球j次试验第一次最好在k=d[i-1][j-1]+1楼进行测试

    同时这也是第一次气球就破的情况下最多可以测到的楼层数d[i][j]=k=d[i-1][j-1]+1。


    如果第一次气球不破,那么我们还剩下i个气球j-1次试验,最多可以再测d[i][j-1]层楼(要仔细考虑,和高度无关),再加上之前的k楼

    第一次气球不破的情况下最多可以测到的楼层数d[i][j]=d[i][j-1]+k=d[i][j-1]+d[i-1][j-1]+1。

    所以,综上分析,i个气球j次试验最多可以测到d[i][j]=d[i][j-1]+k=d[i][j-1]+d[i-1][j-1]+1。


    现在回到题目,【即我们要求的是最少测几次才可以测到n楼。】

    根据递推公式预处理d[i][j]表。

    气球数目为k,楼层为n,只需枚举次数j,当d[k][j]>=n时j即为所求解。

     1 #include <cstdio>
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4 #define LL long long
     5 LL f[110][65];
     6 int k;
     7 LL n;
     8 
     9 int main()
    10 {
    11     memset(f,0,sizeof(f));
    12     for(int i=1;i<=100;i++)
    13         for(int j=1;j<64;j++)
    14             f[i][j]=f[i-1][j-1]+1+f[i][j-1];
    15     while(scanf("%d%lld",&k,&n)&&k)
    16     {
    17         if(f[k][63]<n)
    18         {
    19              puts("More than 63 trials needed.");
    20              continue;
    21         }
    22         for(int i=1;i<=63;i++) if(f[k][i]>=n)
    23         {
    24             printf("%d
    ",i);
    25             break;
    26         }
    27     }
    28     return 0;
    29 }
    View Code

    Team them up!

     UVA - 1627 

     虽然只是个01背包,二分图。。。还是不会写,看起来都费劲。。。

    以后再回来看吧-_-||


    刚刚又去学习了下背包问题九讲,有些东西豁然开朗的感觉。。。

    贴个链接吧http://love-oriented.com/pack/P09.html

    首先是dp里面初始时,d[0][0+n]=1,这是当前一个组也没选的合法状态,差额为本来为0。但是考虑到差额可能为负值,故加上n,因此以下dp的差额全部加了n。

    输出时,因为是dp时是从第一个连通块到最后一个连通块,所以输出时从后往前递推输出结果。

     1 // UVa1627 Team them up!
     2 // Rujia Liu
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<iostream>
     6 #include<vector>
     7 #include<algorithm>
     8 using namespace std;
     9 
    10 const int maxn = 100 + 5;
    11 
    12 int n, G[maxn][maxn], color[maxn], diff[maxn], cc;
    13 vector<int> team[maxn][2]; // team[cc][c] is the list of people in connected-component cc, color c
    14 
    15 // returns false if not bipartite graph
    16 bool dfs(int u, int c) {
    17   color[u] = c;
    18   team[cc][c-1].push_back(u);
    19   for(int v = 0; v < n; v++) {//实际只能通过不满足联接的条件,来确定另外一个队的点集
    20     if(u != v && !(G[u][v] && G[v][u])) { // u and v must be in different groups
    21       if(color[v] > 0 && color[v] == color[u]) return false;
    22       if(!color[v] && !dfs(v, 3-c)) return false;
    23     }
    24   }
    25   return true;
    26 }
    27 
    28 bool build_graph() {
    29   memset(color, 0, sizeof(color));
    30   cc = 0; // current connected-component
    31   for(int i = 0; i < n; i++)
    32     if(!color[i]) {
    33       team[cc][0].clear();
    34       team[cc][1].clear();
    35       if(!dfs(i, 1)) return false;      //可以保证color[i]为0时,设i为1队并不与已有条件冲突
    36       diff[cc] = team[cc][0].size() - team[cc][1].size();
    37       cc++;
    38     }
    39 
    40   return true;
    41 }
    42 
    43 // d[i][j+n] = 1 iff we can arrange first i cc so that team 1 has j more people than team 2.
    44 int d[maxn][maxn*2], teamno[maxn]; 
    45 
    46 void print(int ans) {
    47   vector<int> team1, team2;
    48   for(int i = cc-1; i >= 0; i--) {
    49     int t;
    50     if(d[i][ans-diff[i]+n]) { t = 0; ans -= diff[i]; }
    51     else { t = 1; ans += diff[i]; }
    52     for(int j = 0; j < team[i][t].size(); j++)
    53       team1.push_back(team[i][t][j]);
    54     for(int j = 0; j < team[i][1^t].size(); j++)
    55       team2.push_back(team[i][1^t][j]);
    56   }
    57   printf("%d", team1.size());
    58   for(int i = 0; i < team1.size(); i++) printf(" %d", team1[i]+1);
    59   printf("
    ");
    60 
    61   printf("%d", team2.size());
    62   for(int i = 0; i < team2.size(); i++) printf(" %d", team2[i]+1);
    63   printf("
    ");
    64 }
    65 
    66 void dp() {
    67   memset(d, 0, sizeof(d));
    68   d[0][0+n] = 1;
    69   for(int i = 0; i < cc; i++)
    70     for(int j = -n; j <= n; j++) if(d[i][j+n]) {
    71       d[i+1][j+diff[i]+n] = 1;
    72       d[i+1][j-diff[i]+n] = 1;
    73     }
    74  //每一次安排(即cc++),都是通过目前与所有的其他点的安排没有冲突的点来生成的,所以不论+diff[i]或-diff[i]都没问题
    75 
    76   for(int ans = 0; ans <= n; ans++) {
    77     if(d[cc][ans+n]) { print(ans); return; }
    78     if(d[cc][-ans+n]) { print(-ans); return; }
    79   }
    80 }
    81 
    82 int main() {
    83   int T;
    84   cin >> T;
    85   while(T--) {
    86     cin >> n;
    87     memset(G, 0, sizeof(G));
    88     for(int u = 0; u < n; u++) {
    89       int v;
    90       while(cin >> v && v) G[u][v-1] = 1;
    91     }
    92 
    93     if(n == 1 || !build_graph()) cout << "No solution
    ";
    94     else dp();
    95 
    96     if(T) cout << "
    ";
    97   }
    98   return 0;
    99 }
    lrj

    Fixing the Great Wall

     UVA - 1336

    区间dp

    还是看的别人代码,其实这个题不难,被前几道搞得有心理阴影了。。。

    有一个细节,输入不加!=EOF的话会超时(虽然题目说了以00结束)

     1 #include <cstdio>
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4 const int maxn=1005;
     5 struct node
     6 {
     7     int pos,c,d;
     8     node(int pos=0,int c=0,int d=0):pos(pos),c(c),d(d){}
     9     bool operator <(const node &x) const
    10     {
    11         return pos<x.pos;
    12     }
    13 }p[maxn];
    14 int sum[maxn];
    15 double dp[maxn][maxn][2];
    16 
    17 int main()
    18 {
    19      int n,v,fp;
    20      while(scanf("%d%d%d",&n,&v,&fp)!=EOF&&(n||v||fp))
    21      {
    22         for(int i=0;i<n;i++)
    23             scanf("%d%d%d",&p[i].pos,&p[i].c,&p[i].d);
    24         p[n].pos=fp;p[n].c=0;p[n].d=0;
    25         sort(p,p+n+1);
    26         int w=lower_bound(p,p+n+1,node(fp,0,0))-p;
    27         sum[0]=p[0].d;
    28         for(int i=1;i<=n;i++) sum[i]=sum[i-1]+p[i].d;
    29         //memset(dp,0x3f3f3f3f,sizeof(dp));
    30         for(int i=0;i<=n;i++)
    31             for(int j=i;j<=n;j++) dp[i][j][0]=dp[i][j][1]=0x3f3f3f3f;
    32         dp[w][w][0]=dp[w][w][1]=0;
    33         for(int i=w;i>=0;i--)
    34             for(int j=w;j<=n;j++)
    35         {
    36             double ss=sum[i-1]+sum[n]-sum[j];
    37             if(i!=0)  //往左
    38             {
    39                 //从左到左
    40                 double t=1.0*(p[i].pos-p[i-1].pos)/v;
    41                 dp[i-1][j][0]=min(dp[i-1][j][0],dp[i][j][0]+p[i-1].c+t*ss);
    42                 //从右到左
    43                 t=1.0*(p[j].pos-p[i-1].pos)/v;
    44                 dp[i-1][j][0]=min(dp[i-1][j][0],dp[i][j][1]+p[i-1].c+t*ss);
    45             }
    46             if(j!=n) //往右
    47             {
    48                 //从右到右
    49                 double t=1.0*(p[j+1].pos-p[j].pos)/v;
    50                 dp[i][j+1][1]=min(dp[i][j+1][1],dp[i][j][1]+p[j+1].c+ss*t);
    51                 //从左到右
    52                 t=1.0*(p[j+1].pos-p[i].pos)/v;
    53                 dp[i][j+1][1]=min(dp[i][j+1][1],dp[i][j][0]+p[j+1].c+ss*t);
    54             }
    55         }
    56         int ans=min(dp[0][n][0],dp[0][n][1]);
    57         printf("%d
    ",ans);
    58      }
    59      return 0;
    60 }
    View Code

     感觉后面的DP做不动了,先放放吧。。。等一阵再回来接着做。。。

  • 相关阅读:
    unigui+fastreport报表打印
    MySQL索引类型总结和使用技巧以及注意事项
    Vue.js 和 MVVM
    Go -- 中结构体与字节数组能相互转化
    iOS算法合集
    postman中 form-data、x-www-form-urlencoded、raw、binary的区别
    JS注入
    JS页面间传值
    上手ReactiveCocoa之基础篇
    数据结构与算法题整理
  • 原文地址:https://www.cnblogs.com/yijiull/p/7163832.html
Copyright © 2011-2022 走看看