模拟退火很快乐。。。
#include
typedef long long ll;
using namespace std;
const double dT = 0.997;
const int MAXN = 55;
int m, n;
int tim[MAXN];
int need[MAXN][MAXN], cnt[MAXN];
int pay[MAXN], cost[MAXN];
int vis[MAXN], ansvis[MAXN];
int ans = 0;
char tools[10000];
void readline(int id)
{
scanf("%d", &pay[id]);
memset(tools,0,sizeof(tools));
cin.getline(tools,10000);
int ulen=0,tool;
while(sscanf(tools+ulen,"%d",&tool)==1)
{
need[id][++cnt[id]] = tool;
if(tool==0) ulen++;
else
{
while(tool)
{
tool/=10;
ulen++;
}
}
ulen++;
}
}
int calc()
{
int ret = 0;
memset(tim, 0, sizeof(tim));
for(int i = 1; i <= m; i++)
{
if(!vis[i]) continue;
ret += pay[i];
for(int j = 1; j <= cnt[i]; j++)
{
int tool = need[i][j];
tim[tool]++;
}
}
for(int i = 1; i <= n; i++) if(tim[i]) ret -= cost[i];
return ret;
}
void SA()
{
double T = 1e8;
while(T > 1e-12)
{
int id = rand() % m + 1;
if(vis[id])
{
vis[id] = 0;
int dans = calc();
if(dans > ans)
{
ans = dans;
for(int i = 1; i <= m; i++) ansvis[i] = vis[i];
}
else if(exp((1.0*(dans-ans))/T) * RAND_MAX > rand()) {}
else vis[id] = 1;
}
else
{
vis[id] = 1;
int dans = calc();
if(dans > ans)
{
ans = dans;
for(int i = 1; i <= m; i++) ansvis[i] = vis[i];
}
else if(exp((1.0*(dans-ans))/T) * RAND_MAX > rand()) {}
else vis[id] = 0;
}
T *= dT;
}
}
void output()
{
memset(tim, 0, sizeof(tim));
for(int i = 1; i <= m; i++)
{
if(ansvis[i])
{
printf("%d ", i);
for(int j = 1; j <= cnt[i]; j++) tim[need[i][j]]++;
}
}
putchar(10);
for(int i = 1; i <= n; i++) if(tim[i]) printf("%d ", i);
putchar(10);
printf("%d\n", ans);
}
int main()
{
srand(unsigned(time(0)));
scanf("%d%d", &m, &n);
for(int i = 1; i <= m; i++) readline(i);
for(int i = 1; i <= n; i++) scanf("%d", &cost[i]);
for(int i = 1; i <= 200; i++) SA();
output();
return 0;
}