3/5福建四校联考
1.有3只小猪,三只大猪。大猪和其中一只小猪会划船。船最多可以坐两个人,四只小猪划船的时间是tA,tB,tC,ta,如果载人的话时间翻倍,求最小时间。
题解:暴力搜索。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #define INF 2000000000 #define a A+3 #define b B+3 #define c C+3 #define to 127 using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } int t[10],ans=INF; int s[10]; int has[10]; int d[127]; bool check() { for(int i=4;i<=6;i++) if(has[i]!=has[i-3]) for(int j=1;j<=3;j++) if(j!=i-3&&has[j]==has[i]) return true; return false; } bool check(int x,int y,int k) { if(has[x]==k||has[y]==k)return false; if(x==y)return false; if(!(x>=4)^(y>=4))return true; if(x!=y-3&&y!=x-3)return false; return true; } void dfs(int k,int T,int x) { if(check())return; if(T>=d[x^((k==0)?64:0)])return;else d[x^((k==0)?64:0)]=T; if((x^((k==0)?64:0))==to){ans=min(ans,T);} for(int i=1;i<=4;i++)if(has[i]!=k) {has[i]^=1;dfs(!k,T+t[i],x^s[i]);has[i]^=1;} for(int i=1;i<=4;i++) for(int j=1;j<=6;j++) if(check(i,j,k)) {has[i]^=1;has[j]^=1;dfs(!k,T+2*t[i],x^s[i]^s[j]);has[i]^=1;has[j]^=1;} } int main() { freopen("boat.in","r",stdin); freopen("boat.out","w",stdout); for(int i=0;i<128;i++)d[i]=INF; for(int i=1;i<=4;i++)t[i]=read();s[1]=1; for(int i=2;i<=7;i++)s[i]=s[i-1]<<1; dfs(1,0,0); cout<<ans; return 0;
}
2.有一个n(n<=100)个点m条边的图,可能有负权边,你可以把所有边都加上或减去一个值,求第1个点到第n个点的距离非负的最小值。
题解:不考虑那些到不了n点的点(可以用floyd判一下),然后二分一个答案,判断有没有负环就可以了。复杂度o(能过)
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #define ll long long #define MAXN 100000 #define MAXL 100 #define INF 1000000000 #define inf 2000000000000LL using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } queue<int> q; int n,m,cnt=0; struct edge{ int to,next; ll w; }e[MAXN+5]; bool inq[MAXL+5]; ll mp[MAXL+5][MAXL+5]; ll d[MAXL+5]; int head[MAXL+5]; ll ans=INF; bool yes; inline void ins(int f,int t,int w) { e[++cnt].next=head[f];head[f]=cnt; e[cnt].to=t;e[cnt].w=w; } void dfs(int x,int ad) { if(!yes)return;inq[x]=1; for(int i=head[x];i;i=e[i].next) if(mp[e[i].to][n]<INF&&d[x]+ad+e[i].w<d[e[i].to]) { d[e[i].to]=d[x]+ad+e[i].w;if(inq[e[i].to]){yes=false;return;} dfs(e[i].to,ad); } inq[x]=0; } int main() { freopen("planet.in","r",stdin); freopen("planet.out","w",stdout); int T=read(); while(T--) { n=read();m=read();cnt=0;ans=inf;memset(head,0,sizeof(head)); for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)mp[i][j]=INF; for(int i=1;i<=n;i++)mp[i][i]=0; for(int i=1;i<=m;i++) {int u=read(),v=read(),w=read();ins(u,v,w);mp[u][v]=min(mp[u][v],(ll)w);} for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(mp[i][k]<INF&&mp[k][j]<INF&&mp[i][k]+mp[k][j]<mp[i][j]) mp[i][j]=mp[i][k]+mp[k][j]; int l=-INF,r=INF,mid; while(l<=r) { mid=(l+r)>>1;yes=true;memset(inq,0,sizeof(inq)); for(int i=1;i<=n;i++)d[i]=inf;d[1]=0;dfs(1,mid); if(yes&&d[n]>=0&&d[n]!=inf)r=mid-1,ans=d[n]; else l=mid+1; } if(ans==inf)puts("-1"); else printf("%lld\n",ans); } return 0; }
3.有n个点,每个点有pi堆东西,最多卖掉si堆东西。对于每队1<=i<j<=n,i可以向j运送最多c堆东西,求最多能销售多少堆东西。n<=10000
题解:对于60%,n<=100,就成为了一个裸的网络流模型。每个点向S连pi,向t连si,然后每队点连c的边就可以了。
对于100%,我们发现我们每次做的事情就是求最小割,而这个图的中间的边都是c的,所以我们可以直接考虑每个点割到S还是到T
用f[i][j]表示前i个点,有j个点割到S的最小割。f[i][j]=min(f[i-1][j-1]+p[i]+(i-j)*c,f[i-1][j]+s[i]) 复杂度n^2
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #define ll long long #define INF 2000000000000000LL using namespace std; inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } ll f[2][10005]; ll s[10005]; ll p[10005]; int n;ll c; int main() { freopen("deliver.in","r",stdin); freopen("deliver.out","w",stdout); n=read();c=read(); for(int i=1;i<=n;i++)p[i]=read(); for(int i=1;i<=n;i++)s[i]=read(); int nown=1,pre=0; for(int j=1;j<=n;j++)f[0][j]=f[1][j]=INF; for(int i=1;i<=n;i++) { f[nown][0]=f[pre][0]+s[i]; for(int j=1;j<=i;j++) f[nown][j]=min(f[pre][j-1]+p[i]+(i-j)*c,f[pre][j]+s[i]); nown=1-nown;pre=1-pre; } ll ans=INF; for(int i=0;i<=n;i++) ans=min(ans,f[pre][i]); cout<<ans; return 0; }
4.有一个数字游戏,一开始有两个数1 1,然后每次可以选择其中一个数变成两个数的和。给定最后的状态n,m(<=10^18),求最少已经玩了多少次。
题解:求gcd,gcd是1的时候有解,答案是辗转相除的步数。
这道题居然还有负数,被坑了。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #define ll long long using namespace std; inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } ll ans=-1; ll gcd(ll x,ll y) { if(x<y) {ll t=x;x=y;y=t;} if(y==0)return x;ans+=x/y; return gcd(y,x%y); } int main() { freopen("math.in","r",stdin); freopen("math.out","w",stdout); ll x=read(),y=read(); if(x<=0||y<=0) return 0*puts("-1"); if(gcd(x,y)!=1)puts("-1"); else printf("%I64d\n",ans); return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream