今天一天迷迷糊糊的就没做什么题...好在把最大流理解了,看了半天算法导论把 最小割基本也看懂了,LRJ的书说的太简洁了...
一晚上看一道最小割的题目(HDU2435),但是还是没做出来,痛苦啊,智商不够,还是先去USACO做点题,明天再继续想吧..(好吧,已经12点了...)
USACO 4.1.2 Drainage Ditches (DP+数论)
给几个固定长度,问不能组成的最长长度是多少,如果无限长或不存在输出0.
最简单的是不存在的情况,如果没有1,则1不可能由其它的长度组成,但有了1,所有长度自然都可以组成了...所以当读到1时结果必为0了.
根据数论的知识,这几个数的公约数为gc,如果gc不等于1,那么除了gc倍数以外的数,都不能被组成,简单的例子就是偶数不可能组成奇数..这时结果也为0.
考虑了这两种情况以后,剩下的情况都是有解了,但是这个背包最大是多少呢?不会超过最大数的平方的..然后直接DP就可以了.
/* ID: swm80232 PROG:nuggets LANG: C++ */ #include <cstdio> #include <string> #include <math.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> using namespace std; int n,box[12],d[256*256]; int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } void dp(){ memset(d,0,sizeof d); d[0]=1; for(int i=1;i<=n;i++){ for(int j=box[i];j<=256*256;j++){ if(d[j-box[i]])d[j]=1; } } } int main(){ freopen("nuggets.in","r",stdin); freopen("nuggets.out","w",stdout); scanf("%d",&n); int yes=1,isf=1,gc; for(int i=1;i<=n;i++){ scanf("%d",&box[i]); //如果都不为1,那么1一定不能买到..但只要有1,所有要求都能满足 if(box[i]==1)yes=0; if(i==1)gc=box[1]; else gc=gcd(gc,box[i]); } //如果最大公约数不为1,那么不能整除最大公约数的数都取不到 if(gc!=1)yes=0; if(yes==0){ printf("0\n"); return 0; } dp(); for(int i=256*256-1;i>=1;i--){ if(d[i]==0){ printf("%d\n",i); break; } } //system("pause"); return 0; }
N个长度不同的木板上剪出M个长度不同的木料..剪枝是一门艺术啊..
/* ID: swm80232 PROG:fence8 LANG: C++ */ #include <cstdio> #include <string> #include <math.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> using namespace std; int n,m,a[55],b[1058],c[55],sa[55],sb[1058],res=0,space; int dfs(int st,int pos){ if(st==0)return 1;//到达最短的木棍 //剪枝2:如果剩余空间不足够放所有剩下的木棍 if(space<sb[st])return 0; for(int i=n;i>=pos;i--){ if(c[i]>=b[st]){ c[i]-=b[st]; //剪枝3:如果剩余空间连第一根都不能放了,这个木板就已经没用了 if(c[i]<b[1])space-=a[i]; //剪枝4:如果两根一样长,在a上切[s],在b上切[s+1]和在a上切[s+1],b上切[s]是一样的,所以不用往前搜了 //r~1023 leng~128 所以会有很多长度相同的 if(b[st]==b[st+1]){ if(dfs(st-1,i))return 1 ; }else{ if(dfs(st-1,1))return 1; } //回溯 if(c[i]<b[1])space+=a[i]; c[i]+=b[st]; } } return 0; } bool cmp(int a,int b){return a>b;} int main(){ freopen("fence8.in","r",stdin); freopen("fence8.out","w",stdout); int l=0,r,mid,maxa; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); if(a[i]>maxa)maxa=a[i]; } scanf("%d",&m); r=m;//二分的右端点 for(int i=1;i<=m;i++){ scanf("%d",&b[i]); //剪枝1:比最大的木料长的肯定不能放进去 if(b[i]>maxa)r--; } sort(a+1,a+n+1);//木板从小到大 sort(b+1,b+m+1);//木料从小到大(放的时候从大到小放) sa[0]=sb[0]=0; for(int i=1;i<=n;i++)sa[i]=sa[i-1]+a[i]; for(int i=1;i<=m;i++)sb[i]=sb[i-1]+b[i]; //二分,每次选前mid小的木料 while(l<=r){ memcpy(c,a,sizeof a); mid=(l+r)/2; space=sa[n]; if(dfs(mid,1))l=mid+1; else r=mid-1; } printf("%d\n",(l+r)/2); //system("pause"); return 0; }
最大流,两点之间可能存在多条边,加上去就可以了..EK算法
/* ID: swm80232 PROG:ditch LANG: C++ */ #include <cstdio> #include <string> #include <math.h> #include <string.h> #include <stdlib.h> #include <queue> #include <iostream> #include <algorithm> using namespace std; const int MAXN=202; const int INF=1e8; int n,m,cap[MAXN][MAXN],si,ei,ci; int flow[MAXN][MAXN],a[MAXN],vis[MAXN],p[MAXN],f; void EK(){ memset(flow,0,sizeof flow); queue<int> q; while(1){ memset(a,0,sizeof a); memset(vis,0,sizeof vis); a[1]=INF; vis[1]=1; q.push(1); while(!q.empty()){ int u=q.front(); q.pop(); for(int v=1;v<=m;v++){ if(vis[v]==0&&cap[u][v]>flow[u][v]){ p[v]=u; vis[v]=1; q.push(v); a[v]=min(a[u],cap[u][v]-flow[u][v]); } } } if(a[m]==0)break; for(int i=m;i!=1;i=p[i]){ flow[p[i]][i]+=a[m]; flow[i][p[i]]-=a[m]; } f+=a[m]; } } int main(){ freopen("ditch.in","r",stdin); freopen("ditch.out","w",stdout); memset(cap,0,sizeof cap); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d%d%d",&si,&ei,&ci); cap[si][ei]+=ci; } f=0; EK(); printf("%d\n",f); //system("pause"); return 0; }
二分匹配,以前写过,一段时间不做就忘得差不多了..把二分匹配又复习了一遍
/* ID: swm80232 PROG:stall4 LANG: C++ */ #include <cstdio> #include <string> #include <math.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> using namespace std; int n,m,map[205][205],a,b,vis[205],match[205]; int dfs(int p){ for(int i=1;i<=m;i++){ if(!vis[i]&&map[p][i]){ vis[i]=1; if(match[i]==0||dfs(match[i])){ match[i]=p; return 1; } } } return 0; } int solve(){ memset(match,0,sizeof match); int r=0; for(int i=1;i<=n;i++){ memset(vis,0,sizeof vis); if(dfs(i))r++; } return r; } int main(){ freopen("stall4.in","r",stdin); freopen("stall4.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a); for(int j=1;j<=a;j++){ scanf("%d",&b); map[i][b]=1; } } printf("%d\n",solve()); //system("pause"); return 0; }