考试(三)(标题未取好)

版权声明:不得未经允许转载,否则后果自负 https://blog.csdn.net/qq_41814502/article/details/85293184

目录

思路篇

圆形谷仓

篱笆

代码篇

圆形谷仓

篱笆


思路篇

圆形谷仓

题目描述

农夫约翰有一个圆形的谷仓,谷仓分成了环形的n(3<=n<=100000)个房间,编号为1,2,……n。每个房间有三个门,两个门通往两个相邻的房间,第三个门朝外。约翰有n头奶牛,乱哄哄的在谷仓外面。有的房间门口有多头奶牛排队,有的房间外一头也没有。现在约翰想让每头奶牛都呆在一个房间,他要让奶牛先进入房间,然后按顺时针方向穿过门到其他的房间。奶牛的移动是要消耗能量的,一头奶牛经过d个门需要消耗d2的能量。请问如何消耗最少的能量,完成约翰的任务。

输入

第一行包含n个整数,接下来n行,表示初始时每个房间的奶牛数,保证奶牛数等于n。

输出

一个整数,表示所需要的最小能量。

样例输入

Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

10
1
0
0
2
0
0
1
2
2
2

样例输出

33

首先我们思考一下,是不是一头奶牛走到离自己最远的房间,留出足够的空位,就可以让后面的奶牛少走一点,这样的话也是不是就比走近处的要划算一些?

比如现在有4个房间,有奶牛 2 2 0 0 如果第2个房间其中的一个奶牛走到第3个房间(也就是没有留出位置给后面的奶牛),那么在第1个房间的奶牛就只好走到4,花费10,而我们的第2个房间的奶牛如果留出位置,让后面的奶牛少走一点,走到4,那么花费只要8,你也许会说这个会不会只是特殊?你也可以自己去推导一下,后面奶牛要多少个位置,我们就留多少个,免得后面的奶牛多走,这一定是最优的!

那我们怎么知道这个奶牛要留多少位置?我们可以先让他走到目前的最里面(即离它最远的空房间),保证有位置,后面如果还需要移动时,就再改变就行了,我们用一个队列来保存最远空房间的顺序,既然是最远,我们不妨从n开始从大到小依次入队。如果这个房间有奶牛,那么就一个个移动到最远的空房间!由于是一个环,所以后面的奶牛有可能移到前面去,所以我们还要做一次,一共2圈,我们还要p数组来保存当前的奶牛是从哪里来的,这样就方便计算ans了!

篱笆

题目描述

农夫FJ的奶牛们有空旷恐惧症,所以,FJ打算在他的农场围上篱笆。他的农场是一个矩形区域。左上角的坐标是(0,0),右下角的坐标是(A,B),FJ修建了n(0<=n<=2000)个竖直的篱笆,其横坐标分别为a1,a2,a3,……,an,其中0<ai<A,,每一个篱笆从(ai,0)到(ai,B)也修建了m个水平的篱笆,其纵坐标为b1,b2,b3,……,bm,其中0<bi<B,每一个篱笆从(0,bi)到(A,bi)。这些篱笆把整个农场分成(n+1)*(m+1)个区域。

不幸的是FJ忘了在篱笆上装门了。这导致奶牛无法在不同的区域之间移动。于是他决定将某些篱笆拆掉。现在要使得所有的区域都联通,请问最少要拆掉多长的篱笆。

比如下面这个篱笆

+---+--+

|      |    |

+---+--+

|      |   |  

|      |   |

+---+--+

可以这么拆:

+---+--+

|          |  

+---+  +  

|          |  

|          |

+---+--+

输入

第一题包含四个数A,B,n,m。(0<=A,B<=1000000000).

接下来有两行,第二行n个数,表示a1,a2,……,an,表示竖直的n个篱笆的横坐标,第三行m个数,表示b1,b2,b3,……,bm,表示m个水平的篱笆的纵坐标。

输出

最少要拆除的篱笆的总长度。结果可能超过int。请用long long int

样例输入

Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

15 15 5 2
2
5
10
6
4
11
3

样例输出

44

首先我们可以考虑最小生成树,将每一个格子看做一个点,两个点之间的篱笆就是一条边,这样求最小生成树就可以了。我们排序的时候不需要将每个篱笆都排序,将同一种篱笆看作一起来排,当然,你也需要自己推导出篱笆与顶点序号的关系。

我们也可以贪心。依然还是排序,我们思考,如果要连通,那么肯定是要开一列和一行的。

(开的顺序肯定也是从小到大嘛)开了后,我们想,如果现在已经开了X个列的,那么我现在要开一个行,是不是那一行都要拆?如果不是,那么应该拆多少?

我们从小例子依次举吧!如果X = 2

 按照我们的策略,先删横竖,再按小的依次删。

然后选择一个小的删,由于这里横竖都是2,为了方便,我们先选择竖向的吧,因为我举的例子是X=2嘛

方便大家理解。

 我们就应该是这样了吧,但是我们发现,当我们要删去横的篱笆(1-3)这一段时,发现有一个篱笆不用删,因为他们已经连通了,大家可以发现,当有X个竖篱笆已经处理时,我们的横篱笆就只要去掉m-X+1个就可以了。

也就是这个绿色的不用去,有多少个这种绿色的(不用去的),就是m-X+1个(大家也可以再推一推)

代码篇

圆形谷仓

#include <cstdio>
#include <queue>
#define reg register
using namespace std;
 
inline void read(int &x){
    int f = 1;
    x = 0;
    char s = getchar();
    while(s < '0' || s > '9'){
        if(s == '-'){
            f = -1;
        }
        s = getchar();
    }
    while(s >= '0' && s <= '9'){
        x = (x << 3) + (x << 1) + (s - '0');
        s = getchar();
    }
    x *= f;
}
 
inline void write(long long x){
    if(x < 0){
        putchar('-');
        x *= -1;
    }
    if(x > 9){
        write(x / 10);
    }
    putchar((x % 10) + '0');
}
 
int n, a[100005], wei = -1, p[100005];
queue<int> que;
long long ans;
bool flag;
 
int main(){
    read(n);
    for(reg int i = 0; i < n; i++){
        read(a[i]);
        if(!a[i]){
            wei = i;
        }
        p[i] = i;
    }
    if(wei >= 0)
        que.push(wei);
    wei --;
    while(!que.empty() || !flag){
        wei = (wei + n) % n;
        while(a[wei] && !que.empty()){
            a[wei] --;
            int t = que.front();
            p[t] = p[wei];
            a[t] ++;
            que.pop();
        }
        if(!a[wei]){
            que.push(wei);
        }
        wei --;
        if(wei < 0)
            flag = 1;
    }
    for(reg int i = 0; i < n; i++){
        if(p[i] > i){
            ans += (long long)(n - p[i] + i) * (long long)(n - p[i] + i);
        }
        else {
            ans += (long long)(p[i] - i) * (long long)(p[i] - i);
        }
    }
    write(ans);
    return 0;
}

篱笆

最小生成树

#include <cstdio>
#include <algorithm>
#define reg register
using namespace std;
 
inline void read(int &x){
    int f = 1;
    x = 0;
    char s = getchar();
    while(s < '0' || s > '9'){
        if(s == '-'){
            f = -1;
        }
        s = getchar();
    }
    while(s >= '0' && s <= '9'){
        x = (x << 3) + (x << 1) + (s - '0');
        s = getchar();
    }
    x *= f;
}
 
inline void write(long long x){
    if(x < 0){
        putchar('-');
        x *= -1;
    }
    if(x > 9){
        write(x / 10);
    }
    putchar((x % 10) + '0');
}
 
int x, y, n, m, slb[2005], hlb[2005], p[4005005];
long long ans;
struct node{
    int cha, id;
    bool flag;
    bool operator < (const node &rhs) const {
        return cha < rhs.cha;
    }
}zc[4010];
 
inline void makeSet(){
    for(reg int i = 1; i <= (n + 1) * (m + 1); i++){
        p[i] = i;
    }
}
 
inline int findSet(int x){
    if(x != p[x])
        p[x] = findSet(p[x]);
    return p[x];
}
 
int main(){
    read(x);
    read(y);
    read(n);
    read(m);
    for(reg int i = 1; i <= n; i++){
        read(slb[i]);
    }
    for(reg int i = 1; i <= m; i++){
        read(hlb[i]);
    }
    sort(slb + 1, slb + 1 + n);
    sort(hlb + 1, hlb + 1 + m);
    int o = 0;
    for(reg int i = 1; i <= n; i++){
        zc[++ o].cha = slb[i] - slb[i - 1];
        zc[o].flag = 1;
        zc[o].id = i;
    }
    zc[++ o].cha = x - slb[n];
    zc[o].flag = 1;
    zc[o].id = n + 1;
    for(reg int i = 1; i <= m; i++){
        zc[++ o].cha = hlb[i] - hlb[i - 1];
        zc[o].id = i;
    }
    zc[++ o].cha = y - hlb[m];
    zc[o].id = m + 1;
    sort(zc + 1, zc + 3 + n + m);
    makeSet();
    for(reg int i = 1; i <= n + m + 2; i++){
        if(zc[i].flag){
            for(reg int j = 1; j <= m; j++){
                int u = findSet((j - 1) * (n + 1) + zc[i].id);
                int v = findSet(j * (n + 1) + zc[i].id);
                if(u != v){
                    p[u] = v;
                    ans += (long long)(zc[i].cha);
                }
            }
        }
        else {
            for(reg int j = 1; j <= n; j++){
                int u = findSet((zc[i].id - 1) * (n + 1) + j);
                int v = findSet((zc[i].id - 1) * (n + 1) + j + 1);
                if(u != v){
                    p[u] = v;
                    ans += (long long)(zc[i].cha);
                }
            }
        }
    }
    write(ans);
    return 0;
}

贪心(借鉴一下)

#include<cstdio>
#include<algorithm>
using namespace std;
inline void read(int &x) {
    x=0;
    int f=1;
    char s=getchar();
    while(s<'0'||s>'9') {
        if(s=='-')
            f=-1;
        s=getchar();
    }
    while(s>='0'&&s<='9') {
        x=x*10+s-48;
        s=getchar();
    }
    x*=f;
}
inline void pr(long long x) {
    if(x<0) {
        putchar('-');
        x=-x;
    }
    if(x>9)
        pr(x/10);
    putchar(x%10+48);
}
int A,B,a[2005],b[2005],i,n,j,k,m,x=1,y=1;
long long ans;
int main() {
    read(A),read(B),read(n),read(m);
    for(i=1;i<=n;i++)
        read(a[i]);
    for(i=1;i<=m;i++)
        read(b[i]);
    sort(a+1,a+1+n);
    sort(b+1,b+1+m);
    a[n+1]=A;
    b[m+1]=B;
    for(i=0;i<=n;i++)
        a[i]=a[i+1]-a[i];
    for(i=0;i<=m;i++)
        b[i]=b[i+1]-b[i];
    sort(a,a+1+n);
    sort(b,b+1+m);
    ans=a[0]*m+b[0]*n;
    while(x<=n&&y<=m)
        if(a[x]<=b[y])
            ans+=a[x++]*(m-y+1);
        else
            ans+=b[y++]*(n-x+1);
    pr(ans);
}

猜你喜欢

转载自blog.csdn.net/qq_41814502/article/details/85293184
今日推荐