浙江省第6届程序设计竞赛结题报告汇总 zoj3202-3212

zoj 3202 Second-price Auction

水题,不解释了,直接贴代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

struct node{
	int x;
	int y;
};

struct node number[105];

int cmp(struct node a,struct node b){
	return a.x>b.x;
}
int main(){
	int t;
	scanf("%d",&t);
	int i;
	while(t--){
		int n;
		scanf("%d",&n);
		for(i=0;i<n;i++){
			scanf("%d",&number[i].x);
			number[i].y=i;
		}
		sort(number,number+n,cmp);
		printf("%d %d\n",number[0].y+1,number[1].x);
	}
	return 0;
}

zoj 3203 Light Bulb

简单的数学题,也不解释了,搞成一个双钩函数,最要要注意判断有没有射到墙上即可,直接贴代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;


int main(){
	int t,i;
	scanf("%d",&t);
	while(t--){
		double H,h,D;
		scanf("%lf%lf%lf",&H,&h,&D);
		double tmp=sqrt((H-h)*D);

		if(tmp+h/H*D<D){
			printf("%.3lf\n",h/H*D);
		}
		else if(tmp<D){
			printf("%.3f\n",H+D-tmp-tmp);
		}
		else{
			printf("%.3lf\n",h);
		}
	}
}

zoj 3204 Connect them

最小生成树水题,依旧不解释
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;


struct node{
	int a,b;
	int n;
};

struct rea{
	int a,b;
};

struct node edge[10005];
int father[105];
int cmp(struct node a,struct node b){
	if(a.n==b.n){
		if(a.a==b.a){
			return a.b<b.b;
		}
		else return a.a<b.a;
	}
	return a.n<b.n;
}

int cmp1(struct rea x,struct rea y){
	if(x.a==y.a) return x.b<y.b;
	else return x.a<y.a;
}

int Find(int n){
	if(father[n]==n) return n;
	else return father[n]=Find(father[n]);
}


struct rea relans[500];
int main(){
	int t,i,j;
	scanf("%d",&t);
	while(t--){
		int n;
		scanf("%d",&n);
		int k=0;
		for(i=1;i<=n;i++) father[i]=i;
		for(i=1;i<=n;i++){
			for(j=1;j<=n;j++){
				int tmp;
				scanf("%d",&tmp);
				if(tmp!=0){
					edge[k].a=i;
					edge[k].b=j;
					edge[k++].n=tmp;
				}
			}
		}
		sort(edge,edge+k,cmp);
		int ans=0;
		for(i=0;i<k;i++){
			int ta=Find(edge[i].a);
			int tb=Find(edge[i].b);
			if(ta!=tb){
				father[ta]=tb;
				relans[ans].a=edge[i].a;
				relans[ans++].b=edge[i].b;

			}
			if(ans==n-1) break;
		}
		sort(relans,relans+ans,cmp1);
		if(ans==n-1){
			for(i=0;i<ans;i++){
				if(i==0)
					printf("%d %d",relans[i].a,relans[i].b);
				else 
					printf(" %d %d",relans[i].a,relans[i].b);
			}
			printf("\n");
		}
		else{
			printf("-1\n");
		}
	}
}

zoj 3205 直接贴代码
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<cmath>
using namespace std;

const int mo= 1000000007;


int c[200],p[200][200],a[200];
long long po[105][105];

long long power(int x,int y)
{
    long long res=1;
    long long sum=x;
    while (y) {
            if (y%2==1) res=(res*sum) % mo;
            sum=(sum*sum) % mo;
            y/=2;
    }
    return res;
}

int main()
{
    int t;
    scanf("%d",&t);
    for (int i=0; i<105; i++)
        for (int j=0; j<105; j++)
            po[i][j]=power(i,j);
    while (t) {
            int n,m,k;
            scanf("%d %d ",&n,&m);
            for (int i=0; i<n; i++) {
                scanf("%d",&c[i]);
                for (int j=0; j<m; j++) scanf("%d",&p[i][j]);
            }
            scanf("%d",&k);
            while (k--) {
                    for (int i=0; i<m; i++) scanf("%d",&a[i]);
                    for (int j=0; j<m; j++) {
                            long long ans=0;
                            for (int i=0; i<n; i++) {
                                    long long sum=0;
                                    if (p[i][j]>0) {
                                            sum=c[i]*p[i][j];
                                            for (int k=0; k<m; k++) {
                                                    if (k==j) sum=(sum*po[a[k]][p[i][k]-1] ) % mo;
                                                    else sum=(sum*po[a[k]][p[i][k]]) % mo;
                                            }
                                    }
                                    ans=(ans+sum) % mo;
                            }
                            if (j==m-1) cout<<ans<<endl;
                            else cout<<ans<<" ";
                    }
            }
            if (--t) cout<<endl;
    }
    return 0;
}

zoj 3206  Disaster Area Reconstruction

这道题目还是比较麻烦的,题目是叫你求一个连通分量,这个连通分量里面的顶点数是最多的,并输出这个连通分量。
首先,如果这是一个无环图的话,直接树形DP求出最长链就好,所以就要预先处理成环情况。
接着,只要做一遍强连通分量缩点,然后对每个点记录一个顶点数量,再DP一下即可。 代码如下:
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>

using namespace std;

const int maxn = 50010;
const int inf = 1000000;
int n, m;
vector<int> edge[maxn];

int dfn[maxn], low[maxn], tim;
stack<int>s;
bool instack[maxn];
int belong[maxn], minId[maxn], num[maxn];
int cnt;

void init(){
    for(int i = 0; i <= n; i++)edge[i].clear();
    while(!s.empty())s.pop();
    memset(instack, 0, sizeof(instack));
    memset(num, 0, sizeof(num));
    memset(low, 0, sizeof(low));
    memset(dfn, 0, sizeof(dfn));
    fill(minId, minId+maxn, inf);
    cnt = tim = 0;
}

void tarjan(int u){
    dfn[u] = low[u] = ++tim;
    s.push(u);
    instack[u] = 1;
    int len = edge[u].size();
    for(int i = 0; i < len; i++){
        int v = edge[u][i];
        if(dfn[v] == 0){
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else if (instack[v] == 1){
            low[u] = min(low[u], dfn[v]);
        }
    }
    if (dfn[u] == low[u]){
        int v;
        cnt ++;
        do {
            v = s.top();s.pop();
            instack[v] = 0;

            belong[v] = cnt;//这点缩给哪个新点
            num[cnt]++;//缩了多少点
            minId[cnt] = min(minId[cnt], v);//缩点的最小点标号
        }while(u != v);
    }
}

vector<int> newEdge[maxn];
void build(){
    for(int i = 0; i <= n; i ++)newEdge[i].clear();
    for(int u = 1; u <= n; u++){
        int len = edge[u].size();
        for(int i = 0; i < len; i++){
            int v = edge[u][i];
            if(belong[u] != belong[v]){
                newEdge[belong[u]].push_back(belong[v])    ;
            }
        }
    }
}

int vis[maxn];
int dp[maxn];
int tail[maxn];

void init_new(){
    for(int i = 0; i <= cnt; i++) newEdge[i].clear();
    memset(vis, 0, sizeof(vis));
    memset(dp, 0, sizeof(dp));
}

void dfs(int u){
    vis[u] = 1;
    dp[u] = num[u];
    tail[u] = u;
    int len = newEdge[u].size();
    for(int i = 0; i < len; i++){
        int v = newEdge[u][i];
        if(vis[v] == 0){
            dfs(v);
        }
        if(dp[u] < dp[v]+num[u]){
            dp[u] = dp[v]+num[u];
            tail[u] = tail[v];
        } else if( dp[u] == dp[v]+num[u]){
            if(minId[tail[u]] > minId[tail[v]])
                tail[u] = tail[v];
        }
    }
}

int main(){
    int t;
    int a, b;
    scanf("%d", &t);
    while(t--){
        scanf("%d %d", &n, &m);
        init();

        for(int i = 0; i <m; i++){
            scanf("%d%d", &a, &b);
            edge[a].push_back(b);
        }
        for(int i = 1; i <= n; i++){
            if(dfn[i] == 0){
                tarjan(i);
            }
        }
        int ans = 0;
        init_new();
        build();
        for(int i = 1; i <= cnt; i ++){
            if(vis[i] == 0){
                dfs(i);
            }
        }
        pair<int, int> res = make_pair(inf, inf);
        for(int i = 1; i <= cnt; i ++){
            a = minId[tail[i]], b = minId[i];
            pair<int, int> tmp = make_pair(a, b);
            if(dp[i] > ans){
                ans = dp[i];
                res = tmp;
            } else if( dp[i] == ans ) {
                if ( tmp < res && res.first != res.second || tmp.first == tmp.second ){
                    res = tmp;
                }
            }
        }
        if(res.first == res.second) {
            res = make_pair(1, 2);
        }
        printf("%d\n%d %d\n", ans, res.first, res.second);
    }
}

zoj 3207  80ers' Memory 

水题,不解释了,代码也不上了

zoj 3208 Reforestation

这道题目讲多一点,题目意思是:有一个观测者正在观测周围情况,观测者一直在(0,0)的位置。 题目给你一些树的圆心,这些树每秒钟半径为多1,如果这些树相互碰撞或者碰到了观测者,那它们就会停止生长,它们会挡住观测者的视线,题目问的是观测者什么时候被挡住?如果挡不住的话就输出-1.

思路:
首先可以先预处理出来每颗树什么时候停止生长,就是每棵树和其他所有的树算一个相交时间取最小即可。然后就可以想到二分时间,取所有停止时间中最大的作为最大时间进行二分,对于每一个时间只要计算观测者是否被挡住即可。 具体的计算的话,只需要看是否[0,2π]范围内的视野全被挡住了,如果挡住了,你懂得。
代码如下
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<cmath>
using namespace std;

const double o=1e-8;
const double pi = acos(-1.0);

struct da
{
    double x,y,t;
} a[10000];

struct da1
{
    double l,r;
}q[10000];

int n,bo[400];
double ti[100000];

double min(double x, double y)
{
    return x<y?x:y;
}

double max(double x,double y)
{
    return x>y?x:y;
}
double dis(int i,int j)
{
    return sqrt( (a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y)  );
}

bool cmp(da1 a, da1 b)
{
    return a.l<b.l;
}

bool cmp2(double a,double b)
{
    return a<b;
}

bool check(double res)
{
    int sum=0;
    for (int i=1; i<=n; i++) {
            double r = min(res,a[i].t);
            double ph1,ph2;
            ph1 = atan2(a[i].y,a[i].x);
            if (ph1<0) ph1+=pi*2;
            if ( r-dis(0,i)<o ) ph2 = asin(r/dis(0,i));
            else ph2=pi/2.0;
            double lnow=ph1-ph2,rnow=ph1+ph2;
            if (lnow<0) {
                    q[sum].l=lnow+pi*2;
                    q[sum].r=pi*2;
                    sum++;
                    q[sum].l=0;
                    q[sum].r=rnow;
                    sum++;
            }
            else if (rnow>pi*2) {
                    q[sum].l=lnow;
                    q[sum].r=pi*2;
                    sum++;
                    q[sum].l=0;
                    q[sum].r=rnow-pi*2;
                    sum++;
            }
            else {
                    q[sum].l=lnow;
                    q[sum].r=rnow;
                    sum++;
            }
    }
    sort(q,q+sum,cmp);
    double rnow=o;
    for (int i=0; i<sum; i++) {
            if (q[i].l>rnow) return true;
            rnow = max(rnow,q[i].r);
    }
    if (rnow<pi*2) return true;
    return false;
}

int main()
{
    int t;
    scanf("%d",&t);
    while (t--) {
            scanf("%d",&n);
            a[0].x=0,a[0].y=0; a[0].t=0;
            for (int i=1; i<=n; i++) {
                    int x,y;
                    scanf("%d %d",&x,&y);
                    a[i].x=x,a[i].y=y;
                    a[i].t=999999;
            }
            double l=0.0,r=0.0;
            memset(bo,0,sizeof bo);
            bo[0]=true;
            for (int i=1; i<=n; i++) {
                    int tt=0;
                    double mint=999999;
                    for (int j=1; j<=n; j++) if (!bo[j]) {
                            double tmp=dis(0,j);
                            for (int k=1; k<=n; k++) if (j!=k){
                                    if (!bo[k]) tmp=min(tmp,dis(j,k)/2.0);
                                    else tmp=min(tmp,dis(j,k)-a[k].t);
                            }
                            if (tmp<mint) {
                                    tt=j;
                                    mint=tmp;
                            }
                    }
                    bo[tt]=true; a[tt].t=mint;
            }
            for (int i=1; i<=n; i++) r=max(r,a[i].t);
            r+=1.0;
            if ( check(r) ) cout<<"-1.0"<<endl;
            else {
                while (r-l>1e-8) {
                        double mid=(l+r)/2.0;
                        if (check(mid)) l=mid;
                        else r=mid;
                }
                printf("%.8f\n",l);
            }
    }
    return 0;
}

zoj 3209 Treasure Map

用n*m作为列,每个矩阵作为行,Dancing Link不解释了
#include<stdio.h>
#include<string.h>

const int ROW = 505;
const int V = 452000;
const int LIE = 905;

int R[V],L[V],U[V],D[V],C[V];
int H[ROW],S[LIE];
int n,m;
int size;
int ans;

void link(int r,int c)
{
    S[c]++;C[size]=c;
    U[size]=U[c];D[U[c]]=size;
    D[size]=c;U[c]=size;
    if(H[r]==-1) H[r]=L[size]=R[size]=size;
    else
    {
        L[size]=L[H[r]];R[L[H[r]]]=size;
        R[size]=H[r];L[H[r]]=size;
    }
    size++;
}
void remove(int c)
{
    int i,j;
    L[R[c]]=L[c];
    R[L[c]]=R[c];
    for(i=D[c];i!=c;i=D[i])
    {
        for(j=R[i];j!=i;j=R[j])
        {
            S[C[j]]--;
            U[D[j]]=U[j];
            D[U[j]]=D[j];
        }
    }
}
void resume(int c)
{
    int i,j;
    for(i=U[c];i!=c;i=U[i])
    {
        for(j=L[i];j!=i;j=L[j])
        {
            S[C[j]]++;
            U[D[j]]=D[U[j]]=j;
        }
    }
    L[R[c]]=c;
    R[L[c]]=c;
}


void Dance(int k){
	int Min,i,j,c;
	if(R[0]==0){
		if(ans>k){
			ans=k;
		}
		return ;
	}	
	for(Min=ROW,i=R[0];i;i=R[i]){
		if(Min>S[i]) {
			Min=S[i];
			c=i;
		}
	}
	remove(c);
	for(i=D[c];i!=c;i=D[i]){
		for(j=R[i];j!=i;j=R[j]){
			remove(C[j]);			
		}
		Dance(k+1);
		for(j=L[i];j!=i;j=L[j]){
			resume(C[j]);
		}
	}
	resume(c);
}


int main(){
	int t,i,j,row;
	scanf("%d",&t);
	while(t--){
		int p;
		scanf("%d%d%d",&n,&m,&p);
		int count=n*m;
		for(i=0;i<=n*m;i++){
			S[i]=0;
			U[i]=D[i]=i;
			L[i+1]=i;R[i]=i+1;
		}
		R[n*m]=0;
		size=n*m+1;
		for(row=1;row<=p;row++){
			H[row]=-1;
			int x1,y1,x2,y2;
			scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
			for(i=x1;i<x2;i++){
				for(j=y1;j<y2;j++){
					link(row,i*m+j+1);
				}
			}
		}

		ans=ROW;
		Dance(0);
		if(ans==ROW){
			printf("-1\n");
		}
		else{
			printf("%d\n",ans);
		}
	}
}

zoj 3210 3211 3212 都是水题不解释了



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值