zoukankan      html  css  js  c++  java
  • day 8-20

    1. 妹子 1 问题描述 万人迷皮皮轩收到了很多妹子的礼物,由于皮皮轩觉得每个妹子都不错,所以将她们礼物 的包装盒都好好保存,但长此以往皮皮轩的房间里都堆不下了,所以只能考虑将一些包装盒放 进其他包装盒里节省空间。 方便起见,我们不考虑包装盒的高度和厚度,只考虑包装盒的长宽。 一句话题意:给出两个矩形,问是否可以将一个矩形放在另一个矩形的内部(含边界),多 测。 2 输入格式 输入文件名为girls.in。 第一行,一个整数 n,表示数据组数。 对于下面的每一组数据: 第一行,四个整数 a1,b1,a2,b2 表示两个盒子的长宽。 3 输出格式 输出文件名为girls.out。 n 行,每行一个 ′′Y es′′ 或 ′′No′′(不含引号),分别表示其中一个盒子可以放到另一个盒子 中或两个盒子都不能放到另一个盒子中。

    第一题第一个要注意的点是大对大,小对小,也就是可以旋转。

    第二个点就是可以在侧着放,代码实现还在手打中。。

    2. 旅程 1 背景 您曾经带领着我,穿过我的白天的拥挤不堪的旅程,而到达了我的黄昏的孤寂之境。在通 宵的寂静里,我等待着它的意义。 2 问题描述 神即将带领一些人去他们的孤寂之境,由于这个世界的不稳定,地点之间的有向道路会不 定期地毁坏,出于工作准备,神想知道在某些道路毁坏之后某两点之间的最短路。 就是给定一个有向图,现有两个操作,操作 1 是删除一条边(一条边可重复删除),操作 2 是询问两个点之间的最短路。 3 输入格式 输入文件名为journey.in。 第 1 行两个正整数 n, m,分别表示图的点数和操作数。 第 2 行至第 n + 1 行每行 n 个正整数,为图的邻接矩阵,第 i 行第 j 列的数表示点 i 和点 j 间距离,保证对角线为 0。 接下来 m 行每行三个正整数 c, x, y,c 表示操作种类,为 1 或 2,当 c = 1 时表示删除 x 与 y 相连的边,当 c = 2 时表示询问 x 到 y 的最短路,若不可达则输出 −1。 4 输出格式 输出文件名为journey.out。 输出若干行,每个 2 操作对应一行,答案为询问中 x 到 y 的最短路或 −1

    第二题就是一个删边求最短路问题,比较巧妙的是回溯。先全部删完,用数组记录删掉的边,再回溯就行了。
    #include<bits/stdc++.h>  
    using namespace std;
    const long long inf=0x3f3f3f3f;
    long long n,m,a[205][205],w[100005],op[100005],x[100005],y[100005],ans[100005],cnt;
    int main(){
    	scanf("%lld%lld",&n,&m);
    	for(long long i=1;i<=n;i++)
    	for(long long j=1;j<=n;j++)
    	scanf("%lld",&a[i][j]);
    	for(long long i=1;i<=m;i++)
    	{
    		scanf("%lld%lld%lld",&op[i],&x[i],&y[i]);
    		if(op[i]==1){
    			w[i]=a[x[i]][y[i]];
    			a[x[i]][y[i]]=inf;
    		}
    	}
    	for(long long k=1;k<=n;k++)
    	for(long long i=1;i<=n;i++)
    	for(long long j=1;j<=n;j++){
    		
    		a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
    	}
    	for(long long z=m;z>=1;z--){
    		if(op[z]==1){
    			for(long long i=1;i<=n;i++)
    			for(long long j=1;j<=n;j++){
    			a[i][j]=min(a[i][j],a[i][x[z]]+a[y[z]][j]+w[z]);
    			}
    		}
    		else
    		ans[++cnt]=a[x[z]][y[z]];
    	}
    		for(long long i=cnt;i>=1;i--){
    			if(ans[i]>=inf){
    				printf("-1
    ");
    			}
    			else
    			printf("%lld
    ",ans[i]);
    			}
    		return 0;
    	}

    3. 老大 1 问题描述 因为 OB 今年拿下 4 块金牌,学校赞助扩建劳模办公室为劳模办公室群,为了体现 OI 的 特色,办公室群被设计成了树形(n 个点 n − 1 条边的无向连通图),由于新建的办公室太大 以至于要将奖杯要分放在两个不同的地方以便同学们丢硬币进去开光,OB 想请你帮帮他看看 奖杯放在哪两个办公室使得在任意一个在劳模办公室做题的小朋友能最快地找到奖杯来开光。 一句话题意:给出一个 n 个点的树,在两个合适且不同的点放上奖杯,使得每个点到最近 的奖杯距离最大值最小。 2 输入格式 输入文件名为ob.in。 第一行,一个整数 n。 接下来的 n − 1 行,每行两个数 x y。 3 输出格式 输出文件名为ob.out。 三个数,分别表示最小的最大距离,两个奖杯的位置。

    第三题代码里有很详细的注释。

    #include<bits/stdc++.h>
    using namespace std;
    const int M=2e5+5;
    int head[M],nxt[M<<1],to[M<<1],dis[M],l,r,mid,cnt,n,ans;
    void add(int f,int t)
    {nxt[++cnt]=head[f],head[f]=cnt,to[cnt]=t;
    }
    void dfs(int f,int v,int k)
    {
    	int mx=0,mn=M;//最大值,最小值。 
    	for(int i=head[v];i;i=nxt[i])
    	if(to[i]!=f)//不是环 
    	//这是从后到前的算法。 
    	dfs(v,to[i],k),mx=max(mx,dis[to[i]]+1),mn=min(mn,dis[to[i]]+1);
    	//i为这条边的编号,to[i]为他的终点,dis[to[i]]即为这一个点到最近奖杯的最大值 
    	//深搜下一层,并在之后返回更新mx,mn, 
    	dis[v]=(mx+mn<0?mn:mx);//相比较最大值最小值的绝对值谁更大,即为v的最大距离 
    	if(dis[v]>=k)
    	dis[v]=-k-1,++ans;
    	//这里需要结合前面的 dis[to[i]]+1。前面提到,这个算法是从后到前,后面的都已经大于等于k了,前面的就更不用说了。
    	//但这里并没有做什么特殊处理,遇到前面以这个v为终点时,那时候的dis[v]要么出现另一个。。。。。
    	//分析了这么久,好吧,其实是这样的,只是为了迎合 dis[v]=(mx+mn<0?mn:mx);这个语句来判断dis。
    	//从他的最后一个点开始,依次向前,那时候的mn,mx都是很普通的,且没有负数,dis正常的保存最大值。 
    	//直到找到第一个dis[v]大于等于k的点,累积进去,将这个值赋为-k-1。
    	//之后凡是以这个v为终点的边,mn第一次为-k, 此时需要ma为k才可以。
    	//如果这一次找到了ma除这一条边以外的k,ok,继续累加答案然后成为-k-1,如果没有,就成为-k,下一次需要k-1来解锁
    	//所以,意义何在???
    	//抽象一点想,这是两个奖杯。需要的是两个所有点与他们最近的那个最大相距k的奖杯,。
    	//最终结论: 	
    	//把if(dis[v]>=k) dis[v]=-k-1,++ans;看成放下奖杯。找到了这个点后,后面的不能依靠前面的直接达到k,因为是与最近的奖杯的距离最大值。 
    	//所以ans统计的是放上的奖杯数?
    	//又错,是分段数。两个奖杯将所有分成至少三段。
    	//模拟一下,这里到这里,k个了,嗯,好,分一段,ans++,这里到这里,k个了,嗯,又分一段,这里到这里,嗯?没有k个???
    	//不慌,将k缩小试试,这里不能直接否定,因为第三段不一定需要达到k个。
    	//如果可以分成三段或者超过三段,就扩大试试,反正就是在把第三段分成小于k或者等于k之间徘徊 
    	//还有一个问题,反着做呢???
    	//因为是后面k个,然后从后往前,k个k个的分,所以,所以???
    	//因为是树,所以后往前,从叶子到根点,一定最优。 
    }
    bool check(int k) 
    {
    dfs(ans=0,1,k);
    //起点,终点,每一个点到最近奖杯距离的最大值。又需要所有的情况中最小的那种情况,需要有至少两个大于等于k 
    //所以枚举这个最大值,如果如果有至少两个点满足情况,ok换,没有,ok,换。 
    if(dis[1]>=0)
    ++ans;
    return ans>2;}
    void in()
    {scanf("%d",&n);// 
    for(int i=1,a,b;i<n;++i)//
    scanf("%d%d",&a,&b),add(a,b),add(b,a);//
    }
    void ac()
    {for(l=0,r=n;l^r;)//l^r是终止条件,相同就终止。 
    mid=l+r>>1,check(mid)?l=mid+1:r=mid;//二分。 
    printf("%d",l);
    }
    int main(){
    in(),ac();
    }
  • 相关阅读:
    CF785E Anton and Permutation
    P4054 [JSOI2009]计数问题
    P4396 [AHOI2013]作业
    AD PCB中各层的含义
    AD21 使用手册 快捷键(二)
    AD 汉化和界面恢复
    AD21 使用手册 快捷键(一)
    TINA-TI 安装
    B站下载 视频
    restful-work基本组件
  • 原文地址:https://www.cnblogs.com/xxmxxm/p/11387634.html
Copyright © 2011-2022 走看看