CSP赛前集训【摧毁道路】

摧毁道路

题目描述:(暂不公开)

这道题的数据也是蛮有意思,有六十分是可以拿的。
但是自己写了六十分只拿到五十分。

主要是针对每个数据的弱点吧。
考场代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 3000;
const int INF = 0x3f3f3f3f;

inline int max(int a,int b) { return a > b ? a : b; }

inline int min(int a,int b) { return a < b ? a : b; }

inline void read(int &x)
{
    char ch = getchar(); x = 0;
    for(;ch < '0' || ch > '9';) ch = getchar();
    for(;ch >= '0' && ch <= '9';) x = x * 10 + (ch ^ '0'), ch = getchar();
}

struct Edge{ int to,nxt,val,bz; } g[N << 1];
int last[N],cnt = 1;
int n,m,s1,t1,l1,s2,t2,l2,ans = -1;
int dis[N],dep[20],l,r,q[N << 2],vis[N],fa[N];

void add(int u,int v,int w) { g[++cnt] = (Edge){ v,last[u],w,1 }, last[u] = cnt; }
void Add_Edge(int u,int v,int w) { add(u,v,w), add(v,u,w); }

void work_dis()
{
    memset(dis,INF,sizeof dis), dis[s1] = 0;
    vis[q[l = r = 1] = s1] = 1;
    for(;l <= r; ++ l)
    {
        for(int i = last[q[l]];i;i = g[i].nxt)
            if(dis[g[i].to] > dis[q[l]] + g[i].val)
            {
                dis[g[i].to] = dis[q[l]] + g[i].val;
                if(!vis[g[i].to]) vis[q[++r] = g[i].to] = 1;
            }
        vis[q[l]] = 0;
    }
    if(dis[t1] <= min(l1,l2)) ans = max(ans,m - dis[t1]);
}

void Dfs(int x,int ff)
{
    for(int i = last[x];i;i = g[i].nxt)
        if(g[i].to != ff) dis[g[i].to] = dis[x] + 1, fa[g[i].to] = x, Dfs(g[i].to,x);
}

void work_tree()
{
    memset(dis,INF,sizeof dis); dis[1] = 0;
    Dfs(1,0); int lca = 0,t = 0;
    for(int i = s1;i;i = fa[i]) vis[i]++;
    for(int i = t1;i;i = fa[i])
    {
        if(vis[i]) { lca = i; break; }
        vis[i]++; ++t;
    }
    for(int i = s1;i != lca;i = fa[i]) ++t;
    if(t > l1) return;
    for(int i = fa[lca];i;i = fa[i]) vis[i] = 0; lca = 0;

    for(int i = s2;i;i = fa[i]) vis[i]++; t = 0;
    for(int i = t2;i;i = fa[i])
    {
        if(vis[i]) { lca = i; break; }
        vis[i]++; ++t;
    }
    for(int i = s2;i != lca;i = fa[i]) ++t;
    if(t > l2) return;
    for(int i = fa[lca];i;i = fa[i]) vis[i] = 0;

    int tot = 0;
    for(int i = 1;i <= n; ++ i) 
        if(vis[i]) ++tot;
    
    ans = max(ans,m - tot + 1);
}  

int spfa(int st,int en,int limit)
{
    memset(dis,INF,sizeof dis), dis[st] = 0;
    vis[q[l = r = 1] = st] = 1;
    for(;l <= r; ++ l)
    {
        for(int i = last[q[l]];i;i = g[i].nxt)
            if(dis[g[i].to] > dis[q[l]] + g[i].val && g[i].bz)
            {
                dis[g[i].to] = dis[q[l]] + g[i].val;
                if(!vis[g[i].to]) vis[q[++r] = g[i].to] = 1;
            }
        vis[q[l]] = 0;
    }
    if(dis[en] <= limit) return 1;
    else return 0;
}

int check()
{
    if(spfa(s1,t1,l1) && spfa(s2,t2,l2)) return 1;
    else return 0;
}

void dfs(int x,int k)
{
    if(k > m - max(l1,l2)) return;
    if(x > cnt)
    {
        if(check()) 
			ans = max(ans,k);
        return;
    }
    dfs(x + 2,k);
    g[x].bz = g[x ^ 1].bz = 0, dfs(x + 2,k + 1), g[x].bz = g[x ^ 1].bz = 1;
}

void work() { return; }

int main()
{
    freopen("destroy.in","r",stdin);
    freopen("destroy.out","w",stdout);

    read(n), read(m); ans = -1;
    for(int i = 1,u,v,w;i <= m; ++ i)
        read(u), read(v), w = 1, Add_Edge(u,v,w);
    read(s1), read(t1), read(l1);
    read(s2), read(t2), read(l2);

    if(n <= 15 && m <= 15) dfs(3,0);
    else if(s1 == s2 && t1 == t2) work_dis();
    else if(m == n - 1) work_tree();
    else if(s1 == s2) work();
    else printf("-1");

    ans = ans == INF ? -1 : ans;
    printf("%d",ans);
    fclose(stdin); fclose(stdout);
    return 0;
}

写了很多,但是基本上是模板。

然后这道题正解也不难。
我们可以预处理出每个点两两的最短距离。
这里是 O ( n 2 ) O(n^2) 的。
然后我们就可以再用 O ( n 2 ) O(n^2) 的时间来枚举路径 s 1   t 1 s1~t1 s 2   t 2 s2~t2 交集。
具体做法是枚举中间的一个点。
然后就可以算答案了。没有考场想到。

#include <cstdio>
#include <cstring>
using namespace std;

const int N = 3010;
const int INF = 0x3f3f3f3f;

inline void read(int &x)
{
    char ch = getchar(); x = 0;
    for(;ch < '0' || ch > '9';) ch = getchar();
    for(;ch >= '0' && ch <= '9';) x = x * 10 + (ch ^ '0'), ch = getchar();
}

struct Edge{ int to,nxt,val; } g[N << 1];
int last[N],cnt = 0,ans,l,r,mid,q[N << 2];
int n,m,s1,t1,l1,s2,t2,l2,dis[N][N];

void add(int u,int v,int w) { g[++cnt] = (Edge){ v,last[u],w }, last[u] = cnt; }
void Add_Edge(int u,int v,int w) { add(u,v,w), add(v,u,w); }

int main()
{
    freopen("destroy.in","r",stdin);
    freopen("destroy.out","w",stdout);

    read(n), read(m);
    for(int i = 1,u,v,w;i <= m; ++ i)
        read(u), read(v), w = 1, Add_Edge(u,v,w);
    read(s1), read(t1), read(l1), read(s2), read(t2), read(l2);

    memset(dis,INF,sizeof dis);
    for(int i = 1;i <= n; ++ i)
    {
        dis[i][i] = 0, q[l = r = 1] = i;
        for(;l <= r; ++ l)
            for(int j = last[q[l]];j;j = g[j].nxt)
                if(dis[i][g[j].to] > dis[i][q[l]] + g[j].val)
                    q[++r] = g[j].to, dis[i][g[j].to] = dis[i][q[l]] + g[j].val;
    }

    if(dis[s1][t1] > l1 || dis[s2][t2] > l2) { printf("-1\n"); return 0; }
    ans = m - dis[s1][t1] - dis[s2][t2];

    for(int i = 1;i <= n; ++ i)
        for(int j = 1;j <= n; ++ j)
        {
            if (dis[s1][i] + dis[i][j] + dis[j][t1] <= l1 && dis[s2][i] + dis[i][j] + dis[j][t2] <= l2) 
            {
			    int temp = dis[s1][i] + dis[s2][i] + dis[i][j] + dis[j][t1] + dis[j][t2];
			    if (m - temp > ans) ans = m - temp;
		    }
		    if (dis[s1][i] + dis[i][j] + dis[j][t1] <= l1 && dis[s2][j] + dis[i][j] + dis[i][t2] <= l2) 
            {
			    int temp = dis[s1][i] + dis[i][j] + dis[j][t1] + dis[s2][j] + dis[i][t2];
			    if (m - temp > ans) ans = m - temp;
		    }
        }

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

太可惜了QAQ。

猜你喜欢

转载自blog.csdn.net/INnovate2030/article/details/102809127
今日推荐