zoukankan      html  css  js  c++  java
  • FZOJ 2331 LYK loves graph

    魔改最小斯坦纳树的题。。。

    首先我们发现颜色太多了非常不好处理,一种套路是随机把这些颜色映射到 (k) 种颜色,随机很多次来保证正确性。最后的正确率大概是:

    [1-(1-frac{k!}{k^k})^C ]

    其中 (C) 为随机次数。

    好了现在我们只有 (kle 7) 种颜色了。考虑类似最小斯坦纳树的设状态:设 (f[i][j][s]) 表示包括第 (i) 行第 (j) 列的状态为 (s) 的连通块的最小代价。然后由于是点权所以方程式要稍微变动一下。

    代码:

    #pragma GCC optimize(2)
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<random> 
    
    using namespace std;
    
    mt19937 rnd(0); 
    const int N=20,INF=1<<29;
    int dx[10]={0,-1,0,1,0};
    int dy[10]={0,0,1,0,-1};
    int val[N][N],n,m,k,col[N][N],ans=INF,D[N*N],a[N][N],vis[N][N],f[N][N][2000];
    priority_queue <pair<int,pair<int,int> > > q; 
    
    void init()
    {
    	scanf("%d %d %d",&n,&m,&k);
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			scanf("%d",&a[i][j]);
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			scanf("%d",&val[i][j]);
    }
    
    void Dijkstra(int s)
    {
    	memset(vis,0,sizeof(vis));
    	while(!q.empty())
    	{
    		pair<int,int> p=q.top().second;q.pop();
    		if(vis[p.first][p.second])
    			continue;
    		vis[p.first][p.second]=1;
    		for (int i=1;i<=4;i++)
    		{
    			int tx=p.first+dx[i],ty=p.second+dy[i];
    			if(tx<1||ty<1||tx>n||ty>m||col[tx][ty]==-1)
    				continue;
    			if(f[tx][ty][s]>f[p.first][p.second][s]+val[tx][ty])
    			{
    				f[tx][ty][s]=f[p.first][p.second][s]+val[tx][ty];
    				q.push(make_pair(-f[tx][ty][s],make_pair(tx,ty)));
    			}
    		}
    	}
    }
    
    void work()
    {
    	int T=300;
    	while(T--)
    	{
    		for (int i=0;i<n*m;i++)
    			D[i]=rnd()%k;
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=m;j++)
    				col[i][j]=(a[i][j]!=-1)?D[a[i][j]]:-1;
    		int Max_N=1<<k;
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=m;j++)
    				for (int l=0;l<Max_N;l++)
    						f[i][j][l]=INF;
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=m;j++)
    				if(col[i][j]!=-1)
    					f[i][j][1<<col[i][j]]=val[i][j];
    		for (int s=1;s<Max_N;s++)
    		{
    			for (int i=1;i<=n;i++)
    				for (int j=1;j<=m;j++)
    				{
    					if(col[i][j]==-1) continue;
    					for (int sub=(s-1)&s;sub;sub=(sub-1)&s)
    						f[i][j][s]=min(f[i][j][sub]+f[i][j][s^sub]-val[i][j],f[i][j][s]);
    					if(f[i][j][s]!=INF)
    						q.push(make_pair(-f[i][j][s],make_pair(i,j)));
    				}
    			Dijkstra(s);
    		}
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=m;j++)
    				ans=min(ans,f[i][j][Max_N-1]);
    	}
    	printf("%d
    ",ans==INF?-1:ans);
    }
    
    int main()
    {
    	init();
    	work();
    	return 0;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    Windows server 2016 解决“无法完成域加入,原因是试图加入的域的SID与本计算机的SID相同。”
    Windows Server 2016 辅助域控制器搭建
    Windows Server 2016 主域控制器搭建
    Net Framework 4.7.2 覆盖 Net Framework 4.5 解决办法
    SQL SERVER 2012更改默认的端口号为1772
    Windows下彻底卸载删除SQL Serever2012
    在Windows Server2016中安装SQL Server2016
    SQL Server 创建索引
    C#控制台或应用程序中两个多个Main()方法的设置
    Icon cache rebuilding with Delphi(Delphi 清除Windows 图标缓存源代码)
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13308965.html
Copyright © 2011-2022 走看看