猪猪划船
Description
6只可爱的猪猪们一起旅游,其中有3只大猪A,B,C,他们的孩子为3只小猪a,b,c。由于猪猪们十分凶残,如果小猪在没有父母监护的情况下,和其他的大猪待在一起,就会被吃掉。
拦在他们面前的是一条大河,河上有一只只有1个船桨且限载2只猪的小船,只有A,B,C,a会划船。他们独自划船单程需要的时间为tA,tB,tC,ta,如果搭载另一只猪时间翻倍。你需要求出所有小猪过河的最短时间。
Input
一行,4个整数,tA,tB,tC,ta。
Output
一行,一个整数,表示最短时间。
Sample Input
10 10 10 10
Sample Output
220
HINT
\(tA,tB,tC,ta\leq100\)
Solution
显然是要先将小猪运过去,再把大猪运过去,然后发现此时无合法的方案,再将BbCc大小猪成对运回来,大猪运过去,小猪运过去.
分类讨论一下即可.
#define min(a,b) (a<b?a:b)
int A,B,C,a,ans;
inline void Aireen(){
scanf("%d%d%d%d",&A,&B,&C,&a);
//->bc
ans+=min(a*6,min((a+C)*3,(a+B)*3));
//BC-> Aa-> BbCc<-
ans+=min(B,C)*2+min(A,a)*2+(B+C)*2;
//BC-> a<-
ans+=min(B,C)*2+a;
//bc->
ans+=min(a*5,min(a*2+C*3,a*2+B*3));
printf("%d\n",ans);
}
小猪星球
Description
小猪所在的星系有n个星球,用1~n标号,其中有一些星球之间有单向的隧道相连。由于超时空隧道的存在,通过一个隧道的时间可能为0或负数。现在小猪们决定从1号星球出发,沿着最短路径到达n号星球。
科学家猪小聪发明了一种神奇的装置,使得飞船在每个隧道中运行的时间都增加一个相同的常数(可以为0或负数),你需要确定这个常数使得旅途的总时间非负且最小。
Input
输入文件包含多组数据,第一行为数据组数T。
对于每一组数据,第一行两个整数V,E,表示星球的个数和隧道的个数。
接下来E行,每行3个整数i,j,t,表示从i号星球到j号星球有一条耗时为t的单向隧道。
Output
共T行,每行一个整数,表示从1号星球到n号星球最短的时间。如果不能从1号星球到达n号星球,输出-1。
Sample Input
1
4 5
1 2 1
1 3 1
2 3 -3
3 1 1
3 4 1
Sample Output
2
HINT
\(N\leq{100},E\leq\frac{N(N+1)}{2},|t|\leq10^5,i,j\leq{N}\).
Solution
floyd判当前点是否有可能存在于到n的最短路中,避免spfa判负环的时候在其他点死循环.
现在要求使得图中最短路最短且非负的c.二分判负环即可.
#define N 105
#define M 5055
#define INF 100000
#define inf 505000000
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
int g[N],nxt[M],to[M],w[M],n,m,cnt;
inline void addedge(int x,int y,int z){
nxt[++cnt]=g[x];g[x]=cnt;to[cnt]=y;w[cnt]=z;
}
int b[N][N],q[N*M],d[N],dis[N],h,t;bool inq[N];
inline int chk(int k){
for(int i=1;i<=n;++i) d[i]=0,dis[i]=inf,inq[i]=false;
int u=1;h=1;t=0;q[++t]=u;++d[u];dis[u]=0;inq[u]=true;
while(h<=t){
u=q[h++];inq[u]=false;
for(int i=g[u];i;i=nxt[i]){
if(b[to[i]][n]&&dis[u]+w[i]+k<dis[to[i]]){
dis[to[i]]=dis[u]+w[i]+k;
if(!inq[to[i]]){
if(++d[to[i]]>m) return -1;
inq[to[i]]=true;q[++t]=to[i];
}
}
}
}
return dis[n];
}
inline bool chk1(){
for(int i=1;i<=n;++i) inq[i]=false;
int u=1;h=1;t=0;q[++t]=u;inq[u]=true;
while(h<=t){
u=q[h++];
for(int i=g[u];i;i=nxt[i]){
if(!inq[to[i]]){
q[++t]=to[i];inq[to[i]]=true;
}
}
}
return inq[n];
}
int l,r,mid;
inline void Aireen(){
int t=read();
while(t--){
n=read();m=read();cnt=0;
for(int i=1;i<=n;++i) g[i]=0;
for(int i=1,j,k,w;i<=m;++i){
j=read();k=read();w=read();addedge(j,k,w);
}
if(!chk1()){
puts("-1");continue;
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j) b[i][j]=0;
for(int i=1;i<=n;++i)
for(int j=g[i];j;j=nxt[j]) b[i][to[j]]=1;
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
b[i][j]|=b[i][k]&b[k][j];
b[n][n]=true;
l=-INF;r=INF;
while(l<r){
mid=(l+r)>>1;
if(chk(mid)>=0) r=mid;
else l=mid+1;
}
printf("%d\n",chk(l));
}
}
小猪送货
Description
小猪所在的星系有n个星球从左到右排成一排,用1~n标号。每个星球有建设有一个工厂,住着若干居民。猪粮是猪猪星系的重要的物资,第i个城市的工厂能够生产\(p_i\)个单位的猪粮,第i个城市最多可以卖出\(s_i\)个单位猪粮。对于任意\(1\leq{i<j}\leq{n}\),存在着一条从i到j的单向道路,最多可以通过这条道路运输c个单位的猪粮,你需要计算最多能够卖出多少猪粮。
Input
第一行两个整数n,c.
第二行n个整数,第i个整数表示\(p_i\).
第三行n个整数,第i个整数表示\(s_i\).
Output
一行,一个整数,表示最多可以卖出的猪粮的单位数
Sample Input
5 1
7 4 2 1 0
1 2 3 4 5
Sample Output
12
HINT
\(n\leq{10000},0\leq{c,p_i,s_i}\leq10^9\)
Solution
先考虑网络流建图.
\((s,i)=p_i\;,(i,j)=c(i<j),(i,t)=s_i\).
求最大流.
边数太多很尴尬,考虑DP最小割.
f[i][j]表示前i个点,有j个割与t的连边的最小割.
\(f[i][j]=min\{f[i-1][j]+j\times{c}+p_i\;,f[i-1][j-1]+s_i\}\).
即割掉与s的连边时,其还与t相连,此时j条与t相连的点可以流到它,流向t,所以那j条边也得割掉;割掉与t的连边时,不存在从它流向t的边了.
滚动数组即可.
#define N 10005
#define INF 10000000000000ll
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
typedef long long ll;
ll f[2][N],p[N],s[N],c,ans;
int n;
inline void Aireen(){
n=read();c=1ll*read();
for(int i=1;i<=n;++i) p[i]=1ll*read();
for(int i=1;i<=n;++i) s[i]=1ll*read();
for(int j=0;j<=n;++j) f[0][j]=f[1][j]=INF;
f[1][0]=p[1];f[1][1]=s[1];
for(int i=2;i<=n;++i){
f[i&1][0]=f[i&1^1][0]+p[i];
for(int j=1;j<=n;++j)
f[i&1][j]=min(f[i&1^1][j]+1ll*j*c+p[i],f[i&1^1][j-1]+s[i]);
}
ans=f[n&1][0];
for(int j=1;j<=n;++j)
ans=min(ans,f[n&1][j]);
printf("%lld\n",ans);
}
小猪数数
Description
猪小聪和猪小明在一个小时的时间里,A完了前三题,他们无聊地说:“咱们来玩个游戏消磨时间吧……”
在这个游戏中,猪小聪和猪小明每个人手上有一台电脑,一开始双方的电脑上的数字都是1。现在猪小聪和猪小明按照任意的顺序执行操作a=a+b(其中a为自己电脑上的数字,b为对方电脑上的数字),例如按照小聪-小明-小明执行后双方的数字为2 5。
现在在他们玩了若干轮之后,双方电脑上的数字为N,M,可惜的是他们忘记了他们到底玩了多少轮,你需要求出他们至少玩了多少轮。
Input
2个整数,表示N,M。
Output
1个整数,表示最少玩过的轮数。如果根本不可能出现符合要求的结果,输出-1。
Sample Input
2 5
Sample Output
3
HINT
N,M和ans均不会爆long long.
Solution
类似于更相减损术不除二的步数-1,辗转相除法求一下即可.
typedef long long ll;
ll n,m;
inline ll gcd(ll n,ll m){
if(n<=0||m<=0) return -1ll;
ll r=n%m,ret=n/m-1ll;
while(r){
n=m;m=r;r=n%m;ret+=n/m;
}
if(m>1) return -1ll;
return ret;
}
inline void Aireen(){
scanf("%lld%lld",&n,&m);
printf("%lld\n",gcd(n,m));
}
2017-04-08 17:57:02