130407周赛

1001 哈密顿绕行世界问题

水题

int m ;
bool vis[100];
int aa = 0 ;
int mm[50][50];
int dp[100];
void dfs(int now , int nn)
{
    dp[nn] = now;
    if(nn == 19)
    {
        if(mm[now][m])
        {
            cout <<aa<<": ";
            for (int i = 0 ;i < 20 ;i ++)
            cout <<" "<<dp[i];
            cout <<" "<<m<<endl;
            aa ++ ;
        }
    }
    for (int i = 1 ;i <= 20 ;i ++)
    if(mm[now][i])
    {
        if(!vis[i])
        {
            vis[i] = 1 ;
            dfs(i, nn + 1 );
            vis[i] = 0 ;
        }
    }
}
int main()
{
    mem(mm,0);
    for (int i = 1 ; i <= 20 ; i ++ )
    {
        int a ,b , c ;
        cin >> a >> b >> c ;
        mm[i][a] = 1 ;
        mm[i][b] = 1 ;
        mm[i][c] = 1 ;
    }
    while(scanf("%d",&m) ,m )
    {
        aa = 1 ;
        mem(dp,0);
        mem(vis,0);
        vis[m] = 1 ;
        dfs(m,0);
    }
    return 0;
}
1002 Red and Black

水题

bool vis[100][100];
char mm[100][100];
int n , m ;
int xx[4] = {0 ,0 ,1 ,-1};
int yy[4] = {1,-1,0,0};
int inmap(int x,int y )
{
    if(x >= 0 &&x < m &&y >= 0 &&y < n)return 1;
    return 0;
}
void dfs(int x ,int y )
{
    for (int i = 0 ;i < 4 ; i ++)
    {
        int tx = x + xx[i];
        int ty = y + yy[i];
        if(inmap(tx,ty)&&!vis[tx][ty]&&mm[tx][ty] != '#')
        {
            vis[tx][ty] = 1 ;
            dfs(tx,ty);
        }
    }
}
int main()
{

    while(scanf("%d%d",&n,&m) ,(m + n ))
    {
        mem(vis,0);
        for (int i = 0 ;i < m ;i ++){
            scanf("%s",mm[i]);
        }
        for (int i = 0 ;i < m ;i ++)
        {
            for (int j = 0 ;j < n ;j ++)
            if(mm[i][j] == '@')
            {
                vis[i][j] = 1 ;
                dfs(i,j);
                break;
            }
        }
        int ans = 0 ;
        for (int i = 0 ;i < m ;i ++)
        {
            for (int j = 0 ;j < n ;j ++)
            if(vis[i][j])
            ans ++;
        }
        cout <<ans <<endl;
    }
}

1003 Oil Deposits

水题

int n  , m ;
char mm[105][105];
int xx[8] = {0,0,1,-1,1,1,-1,-1};
int yy[8] = {1,-1,0,0,1,-1,1,-1};
bool vis[105][105];
int inmap(int x,int y)
{
    if(x >= 0 &&x < n &&y >= 0 &&y < m && mm[x][y] != '*')
    return 1;
    return 0;
}
void dfs(int x, int y )
{
    for (int i = 0 ;i < 8 ;i ++)
    {
        int tx = x + xx[i];
        int ty = y + yy[i];
        if(inmap(tx,ty)&&!vis[tx][ty])
        {
            vis[tx][ty] = 1;
            dfs(tx,ty);
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&m) , (n + m ))
    {
        for (int i = 0 ;i < n ;i ++)
        scanf("%s",mm[i]);
        int ans = 0 ;
        mem(vis,0);
        for (int i = 0 ;i < n ;i ++)
        {
            for (int j = 0 ;j < m; j ++)
            {
                if(mm[i][j] == '@' && !vis[i][j])
                {
                    ans ++;
                    dfs(i,j);
                }
            }
        }
        cout <<ans <<endl;
    }
}


1004 Can you solve this equation?

水题

double cal(double x)
{
    double c = 8 * x * x * x * x + 7 * x * x * x + 2 * x * x + 3 * x + 6 ;
    return c;
}
int main()
{
    int T;
    cin >> T;
    while( T -- )
    {
        double x ;
        cin >> x ;
        if(x  < cal(0.0) || x > cal(100.0))
        {
            printf("No solution!\n");
        }
        else
        {
            double  low = 0 ,high = 100;
            double  mid = (low + high) / 2 ;
            while(high - low > 1e-11)
            {
                mid = (high + low ) / 2 ;
                double cc = cal(mid);
                if(cc == x)
                break;
                if(cc < x)
                low = mid ;
                else high = mid ;
            }
            mid = (high + low) / 2 ;
            printf("%.4f\n",mid);
        }
    }
}
1005 Selecting Problems

题意:就是给你一些人,每个人都能做一些题目,然后给出一个人数限制k,问至少有k个人都会做同样的题,问这个题数最大是多少。

思路:题目中给出的题目总数m <= 15,所以可以用二进制表示一个人会做那些题目。

可以先预处理出0 - 2^15 的题目作法 。

这里就发生了做这道题最悲剧的一件事,我直接把每道题扔进一个vector里,想也没想就开始二分了。

然后TLE。我就开始改二分的条件,想着估计是哪个状态没跳出,在mid 那里处理的不好。所以就开始了我的狂T之旅。

贴上vector的预处理。

   for (int i = 0 ;i < 1<<15 ; i ++)
    {
        int num = i ;
        int ans = 0 ;
        while( num )
        {
            if(num & 1 ) ans ++;
            num /= 2;
        }
        qq[ans].push_back(i);
    }
好不容易想到把vector改成数组好了。

    for (int i = 0 ; i < 1<<15 ; i ++)
    {
        int num = i ;
        int ans = 0 ;
        while( num )
        {
            if(num & 1 ) ans ++;
            num /= 2;
        }
        qq[ans][f[ans] ++] = i ;
    }

然而悲剧的事情还没结束。
因为还是T。。。然后我又陷入了狂改mid值的过程当中。。。期间T了无数次。
然后不知道啥想法,我就把交代码的语言改成GUN C ++ .(我这边一直默认是交Visual C++)。。

然后就A了。。。

A了。。。

了。。。

PS:亲测换了语言后如果用vector也是T 。今天你被坑了吗?

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <stack>
#include <map>
#include <iomanip>
#define PI acos(-1.0)
#define Max 2005
#define inf 1<<28
#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
#define FOR(i,s,t) for(int i=(s);i<=(t);++i)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
using namespace std;

string st;
int q[1005];
int n , m , k, ans ;
bool vis[1005];
int qq[20][1<<16];
char ddd[25];
int f[20];
int main()
{
    //mem(f,0);
    //mem(qq,0);
    for (int i = 0 ; i <= 1<<15 ; i ++)
    {
        int num = i ;
        int ans = 0 ;
        while( num )
        {
            if(num & 1 ) ans ++;
            num /= 2;
        }
        qq[ans][f[ans] ++] = i ;
    }
    while(scanf("%d%d%d",&n,&m,&k) != EOF)
    {
        mem(q,0);
        ans=0;
        for (int i = 0 ; i < n ; i ++)
        {
            int a ;
            scanf("%s",ddd);
            scanf("%d",&a);
            while(a -- )
            {
                int x ;
                scanf("%d",&x);
                x --;
                q[i] |= 1 << x;
            }
        }
        int low = 0 ,high = m  ;
        while(high >= low)
        {
            int mid = (high + low) / 2   ;
            int num ;
            int l = f[mid];
            for (int i = 0 ; i < l; i ++)
            {
                num = 0 ;
                for (int j = 0 ; j < n ; j ++)
                {
                    if((q[j] & qq[mid][i]) == qq[mid][i])
                        num ++;
                }
                if(num >= k)
                {
                    ans = mid ;
                    low = mid + 1 ;
                    break;
                }
            }
            if(low <= mid) high = mid - 1 ;

        }
        printf("%d\n",ans);
    }
    return 0;
}

1006 Dwarven Sniper’s hunting

最长距离肯定是子弹的最大射击距离,二分时间,找出最短的时间可以射击到敌人。

double xx1,yy1,xx2,yy2,lx,ly,vd,vb,l;
int main()
{
    while(scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf",&xx1,&yy1,&xx2,&yy2,&lx,&ly,&vd,&vb,&l))
    {
        if(xx1 == 0 && xx2 == 0 && yy1 == 0 && yy2 == 0 && lx == 0 && ly ==0 && vd == 0 && vb == 0 && l ==0 )
        return 0;
        double ftime = (double)l / (double)vb ;//子弹飞的时间
        double left = ftime ,right = 1e7;
        double mid = (left + right ) / 2 ;
        while(right - left > 1e-11)
        {
            mid = (left + right ) / 2 ;
            double nowx = xx1 + lx * mid ;//敌人当前位置
            double nowy = yy1 + ly * mid ;
            double dis = sqrt((xx2 - nowx) * (xx2 - nowx ) + (yy2 - nowy ) * (yy2 - nowy));//俩人的距离
            double dis1 = (mid - ftime) * vd ;//需要跑的距离
            if(dis1 >= fabs(dis - l))
            right = mid ;
            else
            left = mid ;
        }
        mid = (left + right ) / 2;
        printf("%.3f %.3f\n",l,mid);
    }
}


1007 Dome of Circus

三分圆锥的高,求出体积的最小值。记录高和半径。

double a[Max],b[Max],c[Max];
int main()
{
    int T ;
    cin >>  T;
    while ( T -- )
    {
        int n ;
        cin >> n ;
        for(int i = 0 ; i < n ; i ++)scanf("%lf%lf%lf",a + i ,b + i ,c + i );
        double l = 0 , r = 10000 ;
        double h = inf , rr = inf;
        double ansarea = inf;
        while(r - l > 1e-11)
        {
            double mid = (l + r ) / 2;
            double midd = (r + mid ) / 2 ;
            double mr = 0 ;
            double mmr = 0;
            for (int i = 0 ; i < n ; i ++)
            {
                double mm = sqrt(a[i] * a[i] + b[i] * b[i])* mid / (mid - c[i]);//根据比例关系,求出底面半径
                double mmm = sqrt(a[i] * a[i] + b[i] * b[i])* midd / (midd - c[i]);
                if(mr < mm) mr = mm ;//更新半径的最大值
                if(mmr < mmm )mmr = mmm;
            }
            double ansmid = mr * mr * PI * mid / 3 ;
            double ansmidd = mmr * mmr * PI * midd / 3 ;
            if(ansarea > ansmid)
            {
                ansarea = ansmid;
                h = mid;
                rr = mr;
            }
            if(ansarea > ansmidd)
            {
                ansarea = ansmidd ;
                h = midd;
                rr =mmr ;
            }
            if(ansmid > ansmidd)
            {
                l = mid ;
            }
            else
            {
                r = midd;
            }
        }
        printf("%.3f %.3f\n",h,rr);
    }
}
1008 Turn the corner

三分角度,求出最大的过弯y,最后比较判断。

一开始很sb的直接把角度带进三角函数里计算。。。忘了化成pi

double cal(double n ,double x ,double l ,double d)
{
    double xx,yy,c,s;
    s = sin(n);
    c = cos(n);
    xx = -1 * (d / s + c * l) ;
    yy = ( d / c + s * l ) ;
    double tmp = ( 1.0 - x / yy ) * xx * (-1);
    return tmp;
}
int main()
{
    double  l ,d , x , y ;
    while(cin >> x >> y >> l >> d)
    {
        double low = 0 , high = 90.0 ;
        double ans = 0 ;
        while( high - low > 1e-8)
        {
            double mid = (low + high) / 2 ;
            double midd = (low + mid ) / 2 ;
            double amid = cal(mid * PI / 180,x,l,d);
            double amidd = cal(midd * PI / 180,x,l,d);
            ans = max(ans,max(amid,amidd));
            if(amid > amidd)
            {
                low = midd;
            }
            else
            high = mid ;
        }
        if(ans > y)
        cout <<"no"<<endl;
        else
        cout <<"yes"<<endl;
    }
}

1009 Error Curves
题意:给出一堆二次函数,然后求出他们组成的最大值的最小值。。有点拗口。

想一下图形就知道了 。

红色部分是两个二次函数的最大部分,然后最下面那个点就是最小值。所以同样可以用三分求解。

double a[Max],b[Max],c[Max];
double cal(double aa,double bb ,double cc,double xx)
{
    double dd = aa * xx * xx + bb * xx + cc;
    return dd;
}
int main()
{
    int T ;
    cin >>  T ;
    while(  T -- )
    {
        int n ;
        cin >> n ;
        for (int i = 0 ;i < n ;i ++ )
        scanf("%lf%lf%lf",a + i ,b + i ,c + i);
        double l = 0 ;
        double r = 1000.0;
        double  mid = (l + r) / 2 ;
        double ansy = inf;
        while( r - l > 1e-11)
        {
            mid = (l + r ) / 2 ;
            double midmid = (mid + r ) / 2 ;
            double ansmid = -inf ;//一开始这个初值赋成0。。然后就又悲剧了,太粗心了。
            double ansmidmid = -inf ;
            for (int i = 0 ; i < n ;i ++)
            {
                double mm = cal(a[i],b[i],c[i],mid);
                double mmm = cal(a[i],b[i],c[i],midmid);
                if(ansmid < mm)ansmid = mm;
                if(ansmidmid < mmm) ansmidmid = mmm;
            }
            ansy = min(ansy,min(ansmid,ansmidmid));
            if(ansmid > ansmidmid)
            l = mid;
            else
            r = midmid;
        }
        printf("%.4f\n",ansy);
    }
}
1010 湫湫系列故事——设计风景线

接下来介绍这道传说中的坑王之王。

这道题是腾讯马拉松的题,那天比赛的时候我还和学长讨论了一下。问题就集中在这个最长路径,他和我说就是最长路,我说可以是树啊。这个最长路径当时就很迷茫了。赛后去看了 解题报告,写的都是水并查集,然后求最大生成树,然后找出最大值。

当时我就在YY,早知道我就写这道题了。。。(因为题意不明确,当时我就去做1002了,赛后发现是神题。。。)

好了,回到这次比赛的这道题。。

又一次看到这道题,我想都没想直接并查集敲上去,10分钟不到就交了。然后就WA了。。之后改改交交WA了5, 6次之后。。我就觉得不对了。。

我已经完全可以证明我的思路是正确的了。

然后我就出去找到了原题HDU4514 。才发现DISCUSS里面说题意已经改了。。。改成求最长路了。。。

当时我就被雷的里焦外嫩,果然是神坑。

然后就开始重新写了 。

1.判环,我就没改,直接并查集,物尽其用了。

2.找最长路,这部分我一开始用spfa,但是敲着敲着就跑不出来了。。

3.然后我就发现一种很神的办法,就是求树的直径。

树上的最长路就是树的直径。然后可以用两遍BFS解决。

先在这颗树里随意找一点进行BFS,找出最长路的那个节点。

然后对这个节点进行一次BFS,找出的最长路即为这棵树的最长路,也就是直径。

算法正确性证明见:http://blog.sina.com.cn/s/blog_77dc9e0801015m8z.html

4.这道题让我跪了N次的地方,就是我发现居然会MLE。。。

5.然后我就开始各种改数组,还是MLE,只好将判环的并查集改了,将那几个数组都去了。然后用DFS进行判环。

6.这次没MLE了,但是栈溢出了。加了个外挂。然后还是溢出。

7.这次和1005那题是一样的坑,我随手换了个语言Visual C++ 就A了(因为做完1005我就把默认语言改成GUN C++了,而用这个交一直爆栈)。。

这就是这道题的集锦。。下面贴代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <stack>
#include <map>
#include <iomanip>
#define PI acos(-1.0)
#define Max 10001
#define inf 1<<28
#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
#define FOR(i,s,t) for(int i=(s);i<=(t);++i)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
#pragma comment(linker, "/STACK:10240000000000,10240000000000")
using namespace std;

struct kdq
{
    int e ,l ,next;
} ed[Max * 200];
int head[Max * 10] ;
int num ;
int vis[Max * 10] ;
int dis[Max * 10] ;
int ans = 0 ;

void add(int s,int v ,int l)
{
    ed[num].e = v ;
    ed[num].l = l ;
    ed[num].next = head[s];
    head[s] = num ++ ;
}
void init()
{
    mem(head,-1);
    num = 0 ;
    mem(dis,0);
    ans = 0 ;
}
int dfs(int now ,int pre)
{
    vis[now] = 1 ;
    for (int i = head[now ]; i != -1 ; i = ed[i].next)
    {
        int v = ed[i].e ;
        if(v != pre)
        {
            if(vis[v])
                return 0 ;
            if(dfs(v ,now) == 0)
                return 0;
        }
    }
    return 1 ;
}

bool vis1[Max * 10] ;
void bfs(int now )
{
    mem(vis1,0);
    vis1[now] = 1 ;
    dis[now] = 0 ;
    queue<int>qe;
    qe.push(now);//任选一个节点进行BFS
    //qe[0] = now ;
    int v = now ;
    int vv = dis[now] ;
    while(!qe.empty())
    {
        int tt = qe.front();
        //int tt = qe[l ++ ];
        qe.pop();
        for (int i = head[tt] ; i != -1 ; i = ed[i].next)
        {
            int t = ed[i].e ;
            int tl = ed[i].l ;
            if(!vis1[t])
            {
                dis[t] = dis[tt] + tl ;
                vis1[t] = 1 ;
                if(vv < dis[t]) vv = dis[t] , v = t ;//找出最长路的节点
                //qe[r ++ ] = t ;
                qe.push(t) ;
            }
        }
    }
    //if(ans < vv) ans = vv ;
    //mem(vis,0);
    while(!qe.empty())qe.pop();
    qe.push(v);//对这个节点再进行一次BFS
    vis[v] = 1;
    dis[v] = 0 ;
    while(!qe.empty())
    {
        int tt = qe.front() ;
        qe.pop() ;
        for (int i = head[tt] ; i != -1 ; i = ed[i].next)
        {
            int t = ed[i].e ;
            int tl = ed[i].l ;
            if(!vis[t])
            {
                dis[t] = dis[tt] + tl ;
                vis[t] = 1 ;
                if(ans < dis[t])ans = dis[t] ;
                qe.push(t) ;
            }
        }
    }
}
int main()
{
    int n , m ;
    while(scanf("%d%d",&n,&m) != EOF)
    {
        //for (int i = 0 ; i <= n ; i ++)f[i] = i ;
        init();
        for (int i = 0 ; i < m ; i ++)
        {
            int a , b, c ;
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c) ;
            add(b,a,c) ;
        }
        bool flag = 0;
        mem(vis,0);
        for (int i = 1; i <= n ; i ++)
            if(!vis[i])
            {
                if(dfs(i , -1 ) == 0)//dfs判环
                {
                    flag = 1 ;
                    break;
                }
            }
        if(flag)
        {
            cout <<"YES"<<endl;
            continue;
        }
        mem(vis,0) ;
        int k ;
        for (int i = 1 ; i <= n ; i ++)
        {
            if(!vis[i])
            {
                bfs(i);
            }
        }
        printf("%d\n",ans);

    }
}
/*
4 3
1 2 1
2 3 1
3 4 1
*/


革命尚未成功,同志仍需努力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值