zoukankan      html  css  js  c++  java
  • CF1519F Chests and Keys

    一、题目

    点此看题

    ( t zxy)(n) 个宝箱,第 (i) 个宝箱有 (a_i) 个硬币,商店出售 (m) 个钥匙,第 (i) 个钥匙需要 (b_i) 个硬币。

    ( t ppl) 想要趁 ( t zxy) 不在的时候打开他的宝箱拿走硬币,他的收益定义为开宝箱得到的硬币减去买钥匙消耗的硬币,如果收益为正那么 ( t ppl) 就赚了!

    可惜 ( t zxy) 会在 ( t ppl) 来之前给宝箱上锁,第 (i) 把钥匙可以打开第 (i) 把锁,给宝箱 (i) 上锁 (j) 需要花费 (c[i][j])( t zxy) 想知道不让 ( t ppl) 赚钱那么最少需要多少花费,如果 ( t ppl) 稳赚那么输出 (-1)

    (1leq n,mleq 6,1leq a_i,b_ileq 4)

    二、解法

    首先考虑 ( t ppl) 的操作,不难发现这就是一个最大权闭合子图,可以构建出网络流模型:原点连宝箱容量为 (a_i),钥匙连汇点容量为 (b_i),钥匙连它锁了的宝箱,那么赚的钱是 (sum a_i-maxflow),如果 (maxflow=sum a_i) 就不能赚钱。

    ( t zxy) 能决定的就只有宝箱和钥匙之间怎么连边,考虑我们是怎么爆搜的,就是考虑每个钥匙的流量,然后对于每个宝箱都枚举给钥匙多少流量。由于数据范围小得离谱可以考虑状压,设 (dp[s][i][j][k]) 表示宝箱流量的状态是 (s),现在考虑的宝箱是 (i),钥匙是 (j),钥匙的流量是 (k) 的最小花费,转移就照着爆搜写就行了,我算了一下大约 (O(1e7)) 就算的出来。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,k,ans,a[7],b[7],c[7][7],dp[20000][7][7][5];
    struct node {int a[7];node() {memset(a,0,sizeof a);} };
    int get(node s)
    {
    	int x=0;
    	for(int i=1;i<=n;i++) x=x*5+s.a[i];
    	return x;
    }
    node back(int x)
    {
    	node s;
    	for(int i=n;i>=1;i--) s.a[i]=x%5,x/=5;
    	return s;
    }
    int check(node s)
    {
    	for(int i=1;i<=n;i++)
    		if(s.a[i]<a[i]) return 0;
    	return 1;
    }
    signed main()
    {
    	n=read();m=read();k=1;
    	for(int i=1;i<=n;i++)
    		a[i]=read(),k*=5;
    	for(int i=1;i<=m;i++)
    		b[i]=read();
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			c[i][j]=read();
    	memset(dp,0x3f,sizeof dp);
    	ans=inf;dp[0][1][1][0]=0;
    	for(int s=0;s<k;s++)
    	{
    		node t=back(s);int f=1;
    		for(int i=1;i<=n;i++)
    			if(t.a[i]>a[i]) f=0;
    		if(!f) continue;//this state is illegal
    		for(int j=1;j<=m;j++)
    			for(int i=1;i<=n;i++)
    				for(int r=0;r<5;r++)
    				{
    					if(r>b[j]) break;
    					for(int f=0;f<5;f++)
    					{
    						if(r+f>b[j] || t.a[i]+f>a[i]) break;
    						node tt=t;tt.a[i]+=f;
    						int ts=get(tt),ti=i+1,tj=j,tr=r+f,ad=f?c[i][j]:0;
    						if(ti>n) ti=1,tj++,tr=0;
    						if(check(tt)) ans=min(ans,dp[s][i][j][r]+ad);
    						if(tj<=m)
    							dp[ts][ti][tj][tr]=min(dp[ts][ti][tj][tr],dp[s][i][j][r]+ad);
    					}
    				}
    	}
    	if(ans>=inf) puts("-1");
    	else printf("%d
    ",ans);
    }
    
  • 相关阅读:
    MySQL mysqlbinlog 读取mysql-bin文件出错
    MySQL slow_log表不能修改成innodb引擎
    Linux 进程一直占用单核CPU分析
    Linux 磁盘告警分析
    Linux 查看文件被那个进程写数据
    springboot项目访问jsp404
    springboot项目启动控制台显示端口被占用解决方法
    js密码强弱正则校验、邮箱校验
    Java Base64加密解密例子
    mysql按日期做曲线图统计,如果当天没有数据则日期不全、补全日期
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/14728407.html
Copyright © 2011-2022 走看看