[Offer收割]编程练习赛97

链接

[https://hihocoder.com/contest/offers97/problems]

题意

题目1 : 放置矩形
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
小Hi计划在笛卡尔平面中依次放置N个2x1的矩形(矩形的长是2,宽是1,长宽分别与XY轴平行)。其中第i个矩形的左下角预计放置在坐标(Xi, Yi)的位置上。

如果放置某一个矩形时,发现会与之前放置的矩形相交(公共面积大于0),就放弃放置当前矩形,继续尝试下一个矩形。

给定N个矩形的放置顺序,请你帮小Hi计算他一共能放下多少个矩形?

输入
第一行包含一个整数N。

以下N行包含N对整数Xi, Yi。

1 <= N <= 100000

0 <= Xi, Yi <= 1000000

输出
一个整数代表答案

样例输入
3
0 0
1 0
2 0
样例输出
2

分析

就是关键怎么判断我们当前放置的是否和已经放的有重叠
想一下重叠的情况是什么样的?
由于灭有相同的x,y,重叠的情况就是你那个第一条线放在已经放的中间线或者你中间线放置在已经放的第一条线
用一个set维护每一行的状况,后面新来就判断是否重叠即可,看代码吧

代码

#include <bits/stdc++.h>
using namespace std;
const  int N=1e6+10;
int n,ans;
set<int>st[N];
int main() {
	//freopen("in.txt","r",stdin);
	scanf("%d",&n);
	for(int i=1,x,y; i<=n; i++) {
		scanf("%d%d",&x,&y);
		if(st[y].find(x)==st[y].end()&&st[y].find(x+1)==st[y].end()){
			st[y].insert(x);
		    st[y].insert(x+1);
		    		ans++;
		}
	}
	printf("%d\n",ans);
}

题目2 : 两条直线
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
平面上N个点,(X1, Y1), (X2, Y2) ... (XN, YN),已知这N个点都在两条直线y = a1x + b1和y = a2x + b2上(a1 > a2),并且每条直线上至少有10个点。

请你找出这两条直线,即计算出a1, b1和a2, b2。

输入
第一行包含一个整数N。

以下N行每行包含两个实数Xi和Yi。

20 <= N <= 100

-1000000 <= Xi, Yi <= 1000000

输出
输出一行,依次是a1, b1, a2, b2, 保留1位小数。

样例输入
20
2.800 23.480
2.100 5.920
4.900 35.240
9.900 63.240
0.800 12.280
6.400 43.640
6.600 44.760
3.400 7.480
7.600 50.360
3.000 24.600
8.000 13.000
4.300 8.560
3.600 27.960
5.500 38.600
8.900 14.080
0.400 3.880
1.800 5.560
4.200 8.440
4.000 8.200
5.400 9.880
样例输出
5.6 7.8 1.2 3.4

分析

这题就卡你精度问题了
你怎么判断出这两条线呢?
因为最多只有100暴力枚举出第一条
第二条就把不是第一条线上的点暴力枚举就行
然后要求输出的k1>k2就比较一下吧

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
double k1,b1,k2,b2,k3,b3;
double x[110],y[110];
bool vis[110];
int n;
void firstline(){
	for(int i=1;i<n-1;i++)
	for(int j=i+1;j<n;j++)
	{
		k1=(y[j]-y[i])/(x[j]-x[i]),b1=y[j]-k1*x[j];
		for(int r=j+1;r<=n;r++)
		{
			k2=(y[r]-y[j])/(x[r]-x[j]),b2=y[r]-k2*x[r];
			if(k1==k2&&b1==b2) return;
		}
	}
}
void secondline(){
	for(int i=1;i<n-1;i++){
		if(vis[i]) continue;
		for(int j=i+1;j<n;j++)
	   {   
	     if(vis[j]) continue;
		k2=(y[j]-y[i])/(x[j]-x[i]),b2=y[j]-k2*x[j];
		for(int r=j+1;r<=n;r++)
		{
			if(vis[r]) continue;
			k3=(y[r]-y[j])/(x[r]-x[j]),b3=y[r]-k3*x[r];
			if(k3==k2&&b3==b2) return;
		}
	 }
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	//freopen("in.txt","r",stdin);
	while(cin>>n){
		for(int i=1;i<=n;i++)
		cin>>x[i]>>y[i];
		memset(vis,0,sizeof(vis));
		firstline();
		for(int i=1;i<=n;i++)
		if(abs(y[i]-k1*x[i]-b1)<1e-9) vis[i]=1;
		secondline();
		if(k1<k2) swap(k1,k2),swap(b1,b2);
		printf("%.1f %.1f %.1f %.1f\n",k1,b1,k2,b2);
	}
	return 0;
}

题目3 : 有向图可达节点
时间限制:50000ms
单点时限:5000ms
内存限制:256MB
描述
给定一个包含N个节点和M条边的有向图,其中节点的编号是1~N。请你对所有节点计算,从该节点总共可以到达多少个节点?(包含该节点本身)

输入
第一行包含两个整数N和M。

以下M行每行包含两个整数u和v,代表一条从u到v的有向边。

1 <= N <= 10000 0 <= M <= 20000 1 <= u, v <= N

输出
输出N行,每行一个整数。其中第i行代表从i号节点出发可以到达多少节点。

样例输入
4 4
1 2
2 3
1 3
3 4
样例输出
4
3
2
1

分析

就暴力dfs吧,没什么了。时间放宽了5s,要是1s还得优化。我还没写出优化的

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
vector<int> ve[100010];
bool vis[10010];
int dfs(int s){
	int ans=0;
	for(int i=0;i<ve[s].size();i++)
	if(!vis[ve[s][i]])
	{
		vis[ve[s][i]]=1;
		ans+=dfs(ve[s][i]);
	}
	return ans+1;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	//freopen("in.txt","r",stdin);
    int n,m;
    cin>>n>>m;
    int x,y;
    for(int i=1;i<=m;i++){
    	cin>>x>>y;
    	ve[x].push_back(y);
	}
	for(int i=1;i<=n;i++)
	{
		memset(vis,0,sizeof(vis));
		vis[i]=1;
		cout<<dfs(i)<<endl;
	}
	return 0;
}
posted @ 2019-03-24 16:27  ChunhaoMo  阅读(210)  评论(0编辑  收藏  举报