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 都是水题不解释了