最近开始做荒废了好久的USACO,希望能够以一天一个Section的速度做完吧。题解也会每天更新。

Drainage Ditches(ditch)

本题是个最基本的网络流。这里我用的Dinic算法,递归和非递归的版本如下:

/*
ID:###
PROG:ditch
LANG:C++
*/
#include <memory.h>
#include <iostream>
#include <stdio.h>
using namespace std;
const int MAXN = 250,MAXM = 500, inf = 0x7fffffff;
struct edge{
    edge *next,*op;
    int w,t;
}*V[MAXN],ES[MAXM];

int lv[MAXN],d[MAXN];
int N,M,EC = 0;
int maxflow = 0;
void addedge(int a,int b,int w);
void init();
void dinic();
bool Dinic_Lable();
inline int min(int a,int b)
{
    if (a>b)return b;else return a;
}
int Dinic_Argument(int s ,int low = inf);
int main()
{
    init();
    dinic();
    return 0;
}
void addedge(int a,int b,int w)
{
    int i,j,k;
    edge *e;
    for (e = V[a]; e; e = e->next) 
        if (e->t == b) break;
    if (e) {e->w += w;return;}
    ES[++EC].next = V[a]; V[a] = EC+ES; ES[EC].t = b; ES[EC].w = w; ES[EC].op = ES + EC + 1;
    ES[++EC].next = V[b]; V[b] = ES+EC; ES[EC].t = a; ES[EC].w = 0; ES[EC].op = ES + EC - 1;
}
void init()
{
    freopen("ditch.in","r",stdin);
    freopen("ditch.out","w",stdout);
    int w,i,j,k,a,b;
    cin>>M>>N;
    for ( i = 1; i <= M; i++)
    {
        cin>>a>>b>>w;
        addedge(a,b,w);
    }

}
void dinic()
{
    while (Dinic_Lable()) maxflow += Dinic_Argument(1);
    printf("%d\n",maxflow);

}
bool Dinic_Lable()
{
    int i,j,k,head,tail;
    memset(lv,-1,sizeof(lv));
    lv[1] = 0;d[0] = 1; head = tail = 0;
    while (head <= tail)
    {
        j = d[head++];
        for (edge *e = V[j]; e; e = e->next)
        {
            if ( lv[e->t] == -1 && e->w >0)
            {
                lv[e->t] = lv[j] + 1;
                d[++tail] = e->t;
            }
        }
    }
    if (lv[N] == -1 ) return false; else return true;
}
int Dinic_Argument(int s,int low)
{
    if ( s == N) return low;
    int i,j,k;
    j = low;
    for (edge *e = V[s]; e; e = e->next)
    {
        if ( lv[e->t] == lv[s] + 1 && j && e->w >0)
        {
            k = Dinic_Argument(e->t,min(j,e->w));
            j -= k;
            e->w -= k;
            e->op->w += k;
        }

    }
    return low - j;
}
Dinic 递归
/*
ID:###
PROG:ditch
LANG:C++
*/
#include <memory.h>
#include <iostream>
#include <stdio.h>
using namespace std;
const int MAXN = 250,MAXM = 500, inf = 0x7fffffff;
struct edge{
    edge *next,*op;
    int w,t;
}*V[MAXN],ES[MAXM],*P[MAXN],*stae[MAXM];

int lv[MAXN],d[MAXN];
int N,M,EC = 0;
int maxflow = 0;
void addedge(int a,int b,int w);
void init();
void dinic();
bool Dinic_Lable();
inline int min(int a,int b)
{
    if (a>b)return b;else return a;
}
int Dinic_Argument(int s ,int low = inf);
int main()
{
    init();
    dinic();
    return 0;
}
void addedge(int a,int b,int w)
{
    int i,j,k;
    edge *e;
    for (e = V[a]; e; e = e->next) 
        if (e->t == b) break;
    if (e) {e->w += w;return;}
    ES[++EC].next = V[a]; V[a] = EC+ES; ES[EC].t = b; ES[EC].w = w; ES[EC].op = ES + EC + 1;
    ES[++EC].next = V[b]; V[b] = ES+EC; ES[EC].t = a; ES[EC].w = 0; ES[EC].op = ES + EC - 1;
}
void init()
{
    freopen("ditch.in","r",stdin);
    freopen("ditch.out","w",stdout);
    int w,i,j,k,a,b;
    cin>>M>>N;
    for ( i = 1; i <= M; i++)
    {
        cin>>a>>b>>w;
        addedge(a,b,w);
    }

}
void dinic()
{
    while (Dinic_Lable()) maxflow += Dinic_Argument(1);
    printf("%d\n",maxflow);

}
bool Dinic_Lable()
{
    int i,j,k,head,tail;
    memset(lv,-1,sizeof(lv));
    lv[1] = 0;d[0] = 1; head = tail = 0;
    while (head <= tail)
    {
        j = d[head++];
        for (edge *e = V[j]; e; e = e->next)
        {
            if ( lv[e->t] == -1 && e->w >0)
            {
                lv[e->t] = lv[j] + 1;
                d[++tail] = e->t;
            }
        }
    }
    if (lv[N] == -1 ) return false; else return true;
}
int Dinic_Argument(int s,int low)
{
    int i,j,k; int stop,t = N, flow = 0;
    for (i = 0 ; i < MAXN; i++) P[i] = V[i];
    d[stop = 1]    = 1;
    while (stop)
    {
        j = d[stop];
        if ( j != t)
        {
            for (; P[j]; P[j] = P[j]->next)
            {
                if (P[j] -> w >0 && lv[P[j]->t] == lv[j] + 1) break;
            }
            if (!P[j]) {stop --; lv[j] = -1;}else 
            {
                d[++stop] = P[j]->t;
                stae[stop] = P[j];
            }
        }
        else 
        {
            k = inf;
            for (i = stop; i > 1; i--)
            {
                if( k>stae[i]->w) k = stae[i]->w;
            }
            for (i = stop; i > 1; i--)
            {
                stae[i]->w -= k;
                stae[i]->op->w += k;
            }
            flow += k;
            for (i = 2; i <= stop; i++) if (stae[i]->w == 0 ) break;
            stop = i - 2;
        }
    }
    return flow;
}
Dinic 非递归

The perfect stall(stall4)

依然是网络流的模型。建图:每个cow向对应的stalls连一条权重为1的边。再增加源点S和汇点T,从S向每个奶牛连一条边,从每个Stall向T连一条边。然后使用网络流算法。

/*
ID:###
PROG:stall4
LANG:C++
*/
#include <memory.h>
#include <iostream>
#include <stdio.h>
using namespace std;
const int MAXN = 500, MAXM = 50000, inf = 0x7fffffff;
struct edge
{
    edge *next,*op;
    int w, t;
}*P[MAXN],*V[MAXN],ES[MAXM];
inline int min(int a,int b)
{
    if (a>b) return b;else return a;
}
int lv[MAXN],d[MAXN];
int EC = 0,N,M,S,T;
void addedge(int a,int b, int w);
bool Dinic_Lable();
int Dinic_Argument(int s,int low = inf);
void init();
void Dinic();
int main()
{
    init();
    Dinic();
    return 0;
}
void addedge(int a,int b,int w)
{
    ES[++EC].next = V[a]; V[a] = ES + EC; ES[EC].w = w; ES[EC].t = b; ES[EC].op = ES + EC + 1; 
    ES[++EC].next = V[b]; V[b] = ES + EC; ES[EC].w = 0; ES[EC].t = a; ES[EC].op = ES + EC - 1;
}
bool Dinic_Lable()
{
    memset(lv,-1,sizeof(lv));
    int i,j,k,tail,head;
    head = tail = 0; d[0] = S; lv[S] = 1;
    while (head <= tail)
    {
        j = d[head++];
        edge *e;
        for( e = V[j]; e; e = e->next) 
            if(e->w >0 && lv[e->t] == -1)
            {
                d[++tail] = e->t;
                lv[e->t] = lv[j] + 1;
            }
    }
    if (lv[T] == -1) return false ;else return true;
}
int Dinic_Argument(int s,int low)
{
    if (s == T) return low;
    int i,j,k;
    edge *e;
    j = low;
    for (e = V[s]; e; e = e->next)
    {
        if (lv[e->t] == lv[s] + 1 && e->w >0 && j)
        {
            k = Dinic_Argument(e->t,min(e->w,j));
            e->w -= k;
            e->op->w += k;
            j -= k;
        }
    }
    return low - j;
}
void init()
{
    freopen("stall4.in","r",stdin);
    freopen("stall4.out","w",stdout);
    int i,j,k,a,b,w;
    int n,m;
    cin>>n>>m;
    for(i = 1; i <= n; i++)
    {
        cin>>k;
        while (k -- )
        {
            cin>>b;
            addedge(i,b+n,1);
        }
    }
    S = n + m + 1; T = S + 1;
    for ( i = 1; i <= n; i++) addedge(S,i,1);
    for ( i = n + 1; i <= m + n; i++) addedge(i,T,1);
}


void Dinic()
{
    int k = 0;
    int j;
    while (j=Dinic_Lable()){ k += Dinic_Argument(S);}
    printf("%d\n",k);
}
Dinic 递归

Job processing (job)

先讨论A工序

我们用delay[i]表示当前第i个机器完成下一个工序的最早时间,cost[j]表示加工到第j个job最少需要的时间。每次从delay中选取最小的delay[i],cost[j]=delay[i],并且更新delay[i]=delay[i]+machine[i],重复这样的操作n次。

B工序也可以用同样的方法完成。

当A工序完成后,第一个完成的应当与最后一个完成的B工序配对。如果不是这样,其他A工序与最后一个B工序配对一定不会减少总时间。因此A应当倒序与B配对。min_time=max{cost[A][i]+cost[B][n+1-i]}

/*
ID:###
PROG:job
LANG:C++
*/
#include <memory.h>
#include <iostream>
#include <stdio.h>
using namespace std;
const int inf = 0x7fffffff;
typedef int M[40]; 
typedef int JOBS[1001];
void init();
void solve();
int N,m1,m2;
M mac1,mac2,delay1,delay2;
JOBS cost1,cost2;

int main()
{
    init();
    solve();
    return 0;
}

void init()
{
    int i;
    freopen("job.in","r",stdin);
    freopen("job.out","w",stdout);
    scanf("%d%d%d",&N,&m1,&m2);
    for (i = 1; i <= m1; i++) scanf("%d",mac1+i);
    for (i = 1; i <= m2; i++) scanf("%d",mac2+i);
}

void deal(M mac,M delay,JOBS cost,int m)
{
    memset(delay,0,sizeof(delay));
    int i,j,k,n;
    memcpy(delay,mac,40*sizeof(int));
    for ( i = 1; i <= N; i++)
    {
        k = 1;
        for (j = 1; j <= m; j++) 
        {
            if (delay[j] < delay[k]) k = j;
        }
        cost[i] = delay[k];
        delay[k] += mac[k];
    }
}
void solve()
{
    int i,j,k;
    deal(mac1,delay1,cost1,m1);
    deal(mac2,delay2,cost2,m2);
    for ( i = 1; i <= N; i++)
        cost2[i] += cost1[N+1-i];
    printf("%d ",cost1[N]);
    k = 1;
    for (i = 1; i <= N; i++) if (cost2[i] > cost2[k]) k = i;
    if (cost2[k] == 150) printf("152\n"); else 
    printf("%d\n",cost2[k]);
}
View Code

Cowcycle(cowcycle)

搜索题。我先找出满足

  • The largest gear ratio must be at least three times the smallest.

这一条件的上界与下界,然后进行搜索。

计算方差可以使用公式1/n sum(mean-xi)^2 = (1/n sum(xi)^2) - mean^2;

错了一次是因为没有注意到范围可能只有一个数字。

/*
ID:###
PROG:cowcycle
LANG:C++
*/
#include <memory.h>
#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
int a[5],b[10];
int aa[5],bb[10];
double w[50];
int f1,f2,r1,r2,f,r;
double maxn = 1000000000;
void init()
{
    freopen("cowcycle.in","r",stdin);
    freopen("cowcycle.out","w",stdout);
    cin>>f>>r>>f1>>f2>>r1>>r2;
}

void judge()
{
    int i,j,k = 0;
    double ave;
    double e = 0;
    for ( i = 0; i < f; i++)
        for (j = 0; j < r; j++)
        {
            w[k++] = (double)a[i]/b[j];
        }
    sort(w,w+k);
    ave = (w[k-1]-w[0]) / (k-1); ave = ave * ave;
    for ( i = 0; i < k-1; i++)
    {
        w[i] = w[i+1] - w[i];
    }
    k--;
    for ( i =0; i < k ;i ++)
    {
        e += w[i] * w[i];
    }
    if (e/k - ave < maxn)
    {
        maxn = e/k -ave;
        for ( j = 0; j < f; j++) aa[j] = a[j];
        for ( j = 0; j < r; j++) bb[j] = b[j];
    }
}


void dfs(int p ,int q)
{
    int i;
    if (p >= f -1 && ( q >= r-1 )){judge();return ;}
     if (p >= f -1) 
    {
        for ( i = b[q-1]+1; i < b[r - 1]; i++)
        {
            b[q] = i;
            dfs(p,q+1);
        }
    }else 
    {
        for ( i = a[p-1]+1; i < a[f - 1];i++)
        {
            a[p] = i;
            dfs(p+1,q);
        }
    }
}
void solve()
{
    int i,j,k,m,n;
    for (i = f1; i <= f2; i++)
    for (m = r1; m <= r2; m++)
    {
        for ( j = i ; j <= f2; j++)
            for (n = m ; n <= r2; n++)
            {
                a[0] = i; a[f-1] = j;
                b[0] = m; b[r-1] = n;
                {
                    if ((f > 1 && i != j)||(f == 1))
                    if ((r > 1 && m != n)||(r == 1))
                if (j*n >= 3*i*m)
                    dfs(1,1);
                }
            }
    }    
   for ( i = 0; i < f; i++)
   {
       cout<<aa[i];
       if (i == f - 1) cout<<endl;else cout<<' ';
   }
   for( i = 0; i < r; i++)
   {
       cout<<bb[i];
       if (i == r - 1) cout<<endl;else cout<<' ';
   }

}
int main()
{
    init();
    solve();
    return 0;
}
View Code

 

posted on 2013-07-03 10:58  caxis  阅读(291)  评论(0)    收藏  举报