3.24-3.25做题记录

CF213C Relay Race

从左上角走到右下角再回来相当于两个人同时从左上角向右下角走,由于那么我们就可以写出dp,设 f [ i ] [ j ] [ a ] [ b ] f[i][j][a][b] f[i][j][a][b]表示两个人分别走到了 (i,j) 和 (a,b) 的时候的价值和 ,因为 i+j=a+b , 所以可以少记一维,进行转移即可

代码

P2160 [SHOI2007]书柜的尺寸

我们把书按照高度从高到低进行排序,设dp表示 f [ i ] [ a ] [ b ] [ c ] f[i][a][b][c] f[i][a][b][c]表示前 i 本书,三层宽度分别为 a b c的时候三层的高度和,因为a+b+c是前 i 本书的宽度和,所以c这一维可以省去,转移即可

代码

P2157 [SDOI2009]学校食堂

显然(a or b) - (a and b) = (a xor b)
观察数据范围发现bi很小,可以进行状压,而且我们转移需要知道上一个是哪道菜
f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示已经做好了前 i 个菜,且 i - i+7 的状态是 j ,上一道菜是 i+k 的最小时间
k+8作为偏移量即可转移

代码

CF671D Roads in Yusland

因为路径都是祖先关系的,提示我们可以尝试从儿子节点向上计算
计算每种完全覆盖了u子树内的边和u到其父亲边方案,这里我们不能只保留最小值 f,因为可能有的方案覆盖上方的更多,会在以后的转移中更优秀,所以使用一个可并堆去维护

如果一个方案向上延申的不够,我们就把它从堆中删掉
否则就贡献给父亲节点,权值加上其他儿子的 f 值,减去自己的 f 值

代码

ybtoj631. 「左偏树」次短路径

对于这种图上的问题比较难解决,可以尝试转化到树上
先建立最短路树,那么就是限制每个人不能走树上到父亲的边,可以走非树边,问到根节点的最短距离
那么对于点 u ,它的路径一定是这样的:
1.先从u走到u子树内的一点v(包含u)
2.从v走非树边到达w
3.从w走到根

那么考虑我们求出 u 的最短距离需要维护的信息,就是找打这样的点对(v,w)一个在子树内,一个在子树外,如果每个非树边维护一个disv+disw+边权,那么每个点的答案为堆顶-disu

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=4e5+5;
const int inf=0x3f3f3f3f;
int n,m;
vector <PII> G[maxn];
vector <int> T[maxn];
int dis[maxn],vis[maxn];
void dijkstra()
{
    memset(dis,0x3f,sizeof(dis));
    dis[1]=0;
    priority_queue <PII> q;
    q.push(make_pair(0,1));
    while(!q.empty())
    {
        int u=q.top().second;
        q.pop();
        if(vis[u]) continue;
        vis[u]=1;
        for(auto to:G[u])
        {
            int v=to.first;
            if(dis[v]>dis[u]+to.second)
            {
                dis[v]=dis[u]+to.second;
                q.push(make_pair(-dis[v],v));
            }
        }
    }
}
int ex[maxn],ey[maxn],ez[maxn];
int dep[maxn],fa[maxn][21];
void dfs(int u,int f)
{
    dep[u]=dep[f]+1;
    fa[u][0]=f;
    for(int i=1;i<=20;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
    for(auto to:T[u])
    {
        if(to==f) continue;
        dfs(to,u);
    }
}
int lca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=20;i>=0;i--)
        if(dep[fa[x][i]]>=dep[y])
            x=fa[x][i];
    if(x==y) return x;
    for(int i=20;i>=0;i--)
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
vector <int> modify[maxn],del[maxn];
struct tree
{
    int l,r,dis;
    int val;
}tr[maxn];
int de[maxn];
int tot,rt[maxn];
int merge(int x,int y)
{
    if(!x || !y) return x+y;
    if(tr[x].val>tr[y].val) swap(x,y);
    tr[x].r=merge(tr[x].r,y);
    if(tr[tr[x].r].dis>tr[tr[x].l].dis) swap(tr[x].l,tr[x].r);
    tr[x].dis=tr[tr[x].r].dis+1;
    return x;
}
int ans[maxn];
void ddfs(int u,int f)
{
    for(auto to:T[u])
    {
        if(to==f) continue;
        ddfs(to,u);
        rt[u]=merge(rt[u],rt[to]);
    }
    for(auto to:modify[u]) rt[u]=merge(rt[u],to);
    for(auto to:del[u]) de[to]=1;
    while(rt[u] && de[rt[u]]) rt[u]=merge(tr[rt[u]].l,tr[rt[u]].r);
    if(!rt[u]) ans[u]=-1;
    else ans[u]=tr[rt[u]].val-dis[u];
}
int main()
{
    freopen("pal.in","r",stdin);
    freopen("pal.out","w",stdout);
    scanf("%d%d",&n,&m);
    int x,y,z;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        G[x].push_back(make_pair(y,z));
        G[y].push_back(make_pair(x,z));
        ex[i]=x, ey[i]=y; ez[i]=z;
    }
    dijkstra();
    for(int i=1;i<=m;i++)
    {
        if(dis[ex[i]]==inf && dis[ey[i]]==inf) continue;
        if(dis[ex[i]]==dis[ey[i]]+ez[i]) T[ey[i]].push_back(ex[i]);
        if(dis[ey[i]]==dis[ex[i]]+ez[i]) T[ex[i]].push_back(ey[i]);
    }
    dfs(1,0);
    for(int i=1;i<=m;i++)
    {
        if(dis[ex[i]]==inf && dis[ey[i]]==inf) continue;
        if(dis[ex[i]]!=dis[ey[i]]+ez[i] && dis[ey[i]]!=dis[ex[i]]+ez[i])
        {
            x=ex[i]; y=ey[i]; z=lca(x,y);
            modify[x].push_back(++tot);
            tr[tot].dis=0; tr[tot].val=dis[x]+dis[y]+ez[i];
            del[z].push_back(tot);
            modify[y].push_back(++tot);
            tr[tot].dis=0; tr[tot].val=dis[x]+dis[y]+ez[i];
            del[z].push_back(tot);
        }
    }
    ddfs(1,0);
    for(int i=2;i<=n;i++) printf("%d\n",ans[i]);
    return 0;
}

ybtoj601. 「强连通分量」判二分图

先匈牙利判断一下最大匹配是否为n,顺便解出一组解
然后对于有匹配的我们左连右,对于没匹配的边我们右连左
如果一个未被匹配的边在一个强连通分量内,就可以成为匹配的边
因为可以构成类似交错增广路的那种

注意n<m,所以我们需要建立一个虚拟节点
把右侧多的点都连到虚拟节点,保证连通性

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3005;
int n,m;
int a[305][1505];
int vis[maxn],T;
int p[maxn];
bool dfs(int x)
{
    for(int i=n+1;i<=n+m;i++)
    {
        if(!a[x][i] || vis[i]==T) continue;
        vis[i]=T;
        if(!p[i] || dfs(p[i]))
        {
            p[i]=x;
            return 1;
        }
    }
    return 0;
}
vector <int> G[maxn];
int dfn[maxn],low[maxn],dfstime;
int st[maxn],top,in[maxn];
int col[maxn],cnt;
void tarjan(int u)
{
    dfn[u]=low[u]=++dfstime;
    st[++top]=u; in[u]=1;
    for(auto to:G[u])
    {
        if(!dfn[to])
        {
            tarjan(to);
            low[u]=min(low[u],low[to]);
        }
        else if(in[to])
            low[u]=min(low[u],dfn[to]);
    }
    if(low[u]==dfn[u])
    {
        in[u]=0; col[u]=++cnt;
        while(st[top]!=u)
        {
            in[st[top]]=0;
            col[st[top]]=cnt;
            --top;
        }
        --top;
    }
}
int main()
{
    freopen("fantasy.in","r",stdin);
    freopen("fantasy.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            int x; scanf("%1d",&x);
            if(x) a[i][j+n]=x;
        }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        ++T;
        if(dfs(i)) ans++;
    }
    if(ans<n)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                printf("1");
            printf("\n");
        }
        return 0;
    }
    for(int i=1;i<=n;i++)
        for(int j=n+1;j<=n+m;j++)
        {
            if(!a[i][j]) continue;
            if(p[j]==i) G[i].push_back(j);
            else G[j].push_back(i);
        }
    for(int i=n+1;i<=n+m;i++)
    {
        if(p[i]) G[i].push_back(n+m+1);
        else G[n+m+1].push_back(i); 
    }
    for(int i=1;i<=n+m+1;i++) if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;i++)
    {
        for(int j=n+1;j<=n+m;j++)
            if(a[i][j] && (p[j]==i || col[i]==col[j]))
                printf("0");
            else printf("1");
        printf("\n");
    }
    return 0;
}

ybtoj591. 「费用流」愉悦程度

问题难以直接建模,考虑使用解方程的方式计算
列出不等式,加一个delta转化成等式,等式两侧作为流量入和出的守恒建边,先全部假设是睡觉,边权改为吃饭-睡觉用于调整

具体的建边方式见代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1010;
const int inf=0x3f3f3f3f;
int n,k,SS,EE;
int head[maxn],tot=1;
struct edge
{
    int to,nxt;
    ll v,c;
}e[maxn<<4];
void add(int x,int y,ll z,ll val)
{
    e[++tot].to=y; e[tot].nxt=head[x]; e[tot].v=z; e[tot].c=-val; head[x]=tot;
    e[++tot].to=x; e[tot].nxt=head[y]; e[tot].v=0; e[tot].c=val; head[y]=tot;
}
int vals[maxn],vale[maxn];
int S,T,vis[maxn],pre[maxn];
ll dis[maxn];
bool spfa()
{
    queue <int> q;
    for(int i=S;i<=T;i++) vis[i]=0,dis[i]=1e17;
    dis[S]=0; q.push(S); vis[S]=1;
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int to=e[i].to;
            if(e[i].v && dis[to]>dis[u]+e[i].c)
            {
                dis[to]=dis[u]+e[i].c;
                pre[to]=i;
                if(!vis[to]) q.push(to),vis[to]=1;
            }
        }
    }
    return dis[T]!=1e17;
}
ll mcmf()
{
    ll res=0;
    while(spfa())
    {
        ll flow=inf;
        for(int i=T;i!=S;i=e[pre[i]^1].to) flow=min(flow,e[pre[i]].v);
        for(int i=T;i!=S;i=e[pre[i]^1].to) e[pre[i]].v-=flow,e[pre[i]^1].v+=flow;
        res+=flow*dis[T];
    }
    return res;
}
int main()
{
    freopen("delight.in","r",stdin);
    freopen("delight.out","w",stdout);
    scanf("%d%d%d%d",&n,&k,&SS,&EE);
    ll ans=0;
    for(int i=1;i<=n;i++) scanf("%d",&vals[i]),ans+=vals[i];
    for(int i=1;i<=n;i++) scanf("%d",&vale[i]);
    add(0,1,k-SS,0); add(1,2,k-SS-EE,0);
    for(int i=1;i<=k;i++) add(1,i+1,1,vale[i]-vals[i]);
    for(int i=1;i<n;i++) add(i+1,i+2,k-SS-EE,0);
    for(int i=1;i+k<=n;i++) add(i+1,i+k+1,1,vale[k+i]-vals[k+i]);
    for(int i=n-k+1;i<=n;i++) add(i+1,n+2,inf,0);
    S=0; T=n+2;
    printf("%lld\n",ans-mcmf());
    return 0;
}

ybtoj571. 「二分图匹配」炸弹游戏

如果不存在硬石头,我们可以把每个可以放炸弹的位置(x,y),x->y+n连上边,求二分图最大匹配

考虑有硬石头,把横着的一段不存在硬石头和竖着的一段不存在硬石头的段分别作为二分图左侧和右侧,按照连通块编号计算即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
char s[55][55];
int vis[5001],bl[5001];
int tot,idx[55][55],idy[55][55];
vector <int> G[5001];
void add(int x,int y)
{
    G[x].push_back(y);
}
int dfs(int u)
{
    for(auto to:G[u])
    {
        if(!vis[to])
        {
            vis[to]=1;
            if(!bl[to] || dfs(bl[to]))
            {
                bl[to]=u;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    freopen("bomb.in","r",stdin);
    freopen("bomb.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(s[i][j]=='#') continue;
            if(j==1 || s[i][j-1]=='#') tot++;
            idx[i][j]=tot;
        }
    }
    for(int j=1;j<=m;j++)
        for(int i=1;i<=n;i++)
        {
            if(s[i][j]=='#') continue;
            if(i==1 || s[i-1][j]=='#') tot++;
            idy[i][j]=tot;
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(s[i][j]=='*')
                add(idx[i][j],idy[i][j]);
    int res=0;
    for(int i=1;i<=tot;i++)
    {
        memset(vis,0,sizeof(vis));
        if(dfs(i)) res++;
    }
    printf("%d\n",res);
    return 0;
}

ybtoj582. 「网络流」大收藏家

S连每个人容量为1,表示每个人有一种宝物可以产生贡献,第一个人连T容量为a1
然后拆点,每层只需要保留有用的节点,每个人拆开的点,可以向自己的下一个状态保留ai,表示自己的最大容量

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=30005;
int TT,n,m;
int head[maxn],S,T,tot;
struct edge
{
    int to,nxt,v;
}e[maxn<<4];
void add(int x,int y,int z)
{
    // printf("%d %d %d\n",x,y,z);
    e[++tot].to=y; e[tot].nxt=head[x]; e[tot].v=z; head[x]=tot;
    e[++tot].to=x; e[tot].nxt=head[y]; e[tot].v=0; head[y]=tot;
}
int bh,a[maxn];
map <int,int> id[maxn];
int maxflow;
int dep[maxn];
bool bfs()
{
    queue <int> q;
    q.push(S);
    for(int i=S;i<=T;i++) dep[i]=-1;
    dep[S]=0;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=e[i].nxt)
        {
            int to=e[i].to;
            if(e[i].v && dep[to]==-1)
            {
                dep[to]=dep[u]+1;
                q.push(to);
            }
        }
    }
    return dep[T]!=-1;
}
int dfs(int u,int flow)
{
    if(u==T) return flow;
    int res=0;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(dep[to]==dep[u]+1 && e[i].v)
        {
            int tmp=dfs(to,min(flow,e[i].v));
            e[i].v-=tmp; e[i^1].v+=tmp;
            res+=tmp; flow-=tmp;
        }
    }
    if(!res) dep[u]=-1;
    return res;
}
void dinic()
{
    maxflow=0;
    while(bfs())
    {
        maxflow+=dfs(S,inf);
    }
    return ;
}
int main()
{
    freopen("collection.in","r",stdin);
    freopen("collection.out","w",stdout);
    scanf("%d",&TT);
    while(TT--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<=bh+1;i++) head[i]=0;
        tot=1; bh=0;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++) id[i].clear(),id[i][1]=++bh;
        int x,y;
        scanf("%d%d",&x,&y); add(id[x][1],id[y][1],1),add(id[y][1],id[x][1],1);
        for(int i=2;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            id[x][i]=++bh; id[y][i]=++bh;
            add(bh-1,bh,1); add(bh,bh-1,1);
        }
        for(int i=1;i<=n;i++)
        {
            int lst=0;
            map <int,int> &s=id[i];
            for(map <int,int>::iterator it=s.begin();it!=s.end();it++)
            { 
                if(!lst)
                    add(S,it->second,1);
                else add(lst,it->second,a[i]);
                lst=it->second;
            }
        }
        T=bh+1;
        add((--id[1].end())->second,T,a[1]);
        dinic();
        printf("%d\n",maxflow);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
4S店客户管理小程序-毕业设计,基于微信小程序+SSM+MySql开发,源码+数据库+论文答辩+毕业论文+视频演示 社会的发展和科学技术的进步,互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。手机具有便利性,速度快,效率高,成本低等优点。 因此,构建符合自己要求的操作系统是非常有意义的。 本文从管理员、用户的功能要求出发,4S店客户管理系统中的功能模块主要是实现管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理,用户客户端:首页、车展、新闻头条、我的。门店客户端:首页、车展、新闻头条、我的经过认真细致的研究,精心准备和规划,最后测试成功,系统可以正常使用。分析功能调整与4S店客户管理系统实现的实际需求相结合,讨论了微信开发者技术与后台结合java语言和MySQL数据库开发4S店客户管理系统的使用。 关键字:4S店客户管理系统小程序 微信开发者 Java技术 MySQL数据库 软件的功能: 1、开发实现4S店客户管理系统的整个系统程序; 2、管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理等。 3、用户客户端:首页、车展、新闻头条、我的 4、门店客户端:首页、车展、新闻头条、我的等相应操作; 5、基础数据管理:实现系统基本信息的添加、修改及删除等操作,并且根据需求进行交流信息的查看及回复相应操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值